Releases: ymm-oss/fsl
Release list
v4.4.1
- Fixed (#761): the legacy replay trace object wrapper is now exactly
{"events": [...]}—
a misspelled key (for exampleeventz), a non-arrayeventsvalue, or extra keys are
rejected with the wrapper diagnostic instead of being silently tolerated. Focused native
accepting and rejecting contracts pin the wrapper and its full public projection, and a
new liveness-witness replay matrix rejects isolated state, action, and loop corruptions
of everyleadsTolasso case the retired Python comparison covered. - Fixed (#786): the frozen Python compatibility reference now lets an explicit
inlineimplementsaction correspondence override the same requirements-process
auto map, so the manual dialect-conformance corpus no longer rejects a valid
arity-changing refinement mapping. - Fixed (#826): unresolved indexed
initwrites now conservatively collide with every concrete key on the same logical map root instead of silently accepting aliasing writes with equal values. - Fixed (#832): native
fslc checknow fails closed for compose alias and typed
binder resolution gaps thatverifyalready rejected. A declared alias no
longer authorizes a nonexistent qualified type such ascore.NoSuchType, and
an undeclared alias-shaped expression in aninit ifcondition receives the
same type check as an assignment right-hand side. Unknown typed binder names
are also rejected uniformly in properties, action postconditions, and init.
Errors retain the author's spelling and source location; valid imported types,
binder types, and state conditions remain accepted. - Fixed (#904): legacy solver-free BFS now excludes intended
terminalstates from deadlock reporting while preserving true deadlocks, matching explicit BFS and symbolic BMC. - Required (#742): merge readiness now rejects Git-tracked citations to missing
docs/DESIGN-*.mdsections, including colon and explicit-section forms, without
letting untracked documents satisfy them; calibrated folded, list-tail, historical,
and accepting controls preserve the boundary. - Required (#746): the five frozen-Python and DESIGN-index coupled-change metatests now run in the required pre-merge automation lane while remaining outside the Rust-native product gate.
- Required (#761): native Rust tests now bind every corpus
verifyresult class to
its exact public process exit code; pin the business, requirements, and governance
induction CLI contracts; exercise all nine leadsTo case-by-corruption replay cells
with exact diagnostics; compare the complete legacy object-wrapper envelopes
while rejecting wrong keys, value types, and extra root keys; compare the
complete stablerefineenvelope projection with a live, reasoned exclusion for
solver-selected implementation traces; and own all sixteen stable induction
envelope/exit cases with live exclusions and negative controls before the Python
parity harnesses are retired. - Required (#898): Merge readiness now runs ShellCheck with masked-return analysis and fail-closed tracked-script enumeration, plus a calibrated direct-syntax Bash-version guard lint that scans expansions in unquoted heredocs, ignores literal heredoc data, and documents its dynamic-execution boundary.
- Required (#761): the sixteen induction CLI cases the retired Python parity harness compared
are now owned by a native golden contract (induction_cli_contract.rs) — full stable
envelopes with reason-coded, live-hit-checked exclusions, a calibrated cache-mode control,
and an idempotent golden regeneration path. - Required (#761): refinement corpus parity now compares the full stable projection of every
corpus envelope against a checked-in golden with reason-coded exclusions and a
dead-exclusion check, replacing the result/kind/exit-only assertion the retired Python
harness was stronger than. - Documented (#757): recorded the first natural production partial re-run — a GitHub-side
artifact-service transient failed one test shard on a docs-only PR,gh run rerun --failed
re-ran only that shard, and the aggregator accepted the mixed-attempt cohort
(attempts=1,1,2), recovering in one shard's time instead of a full three-shard re-run. - Documented (#761): recorded all 17 Python/Rust parity-harness dispositions and deletion preconditions without deleting a harness, including seven native-owner gaps, the full-envelope helper dependency, the parked Phase-3 comparison, three native-migration candidates, and five bounded manual controls.
- Documented (#904): accepted the #761 native BFS/BMC migration plan, including the
checked 20-model decision matrix, bidirectional witness validation, terminal-aware
deadlock repair, rejecting controls, and safe Python-harness and helper-binary
retirement order. - Required (#906): the induction contract golden is now part of the release-commit
regeneration set. It records each envelope'sversionsblock, so a version bump made the
complete product gate fail comparing the previous version against the new one;docs/RELEASE.md
step 6 now names itsUPDATE_INDUCTION_CLI_CONTRACTregeneration and
is_release_bump_pathnames the golden, keeping the release commit exempt from a
fragment for that path.
v4.4.0
- Changed (#760): native CLI tests now cover deterministic DOT and Mermaid
analysis export, DOT escaping from valid FSL input, and rejection of non-graph
export requests. - Fixed (#617): Normalize Windows source-path separators in the optional-verdict census so classifications and consumer checks remain live across platforms.
- Fixed (#741):
tools/build_site_reference.pynow rejects adocs/LANGUAGE.ja.mdthat
reorders##sections relative todocs/LANGUAGE.mdwhile keeping the section count equal.
render_language_tree()previously compared onlylen(ja_sections) == len(en_sections)and
then paired the two files positionally, so a same-count reorder passed generation silently and
attached a Japanese section body to the wrong English anchor and blurb — exactly the drift
docs/DESIGN-docs-site.mdD7 and this tool's own docstring already claimed was caught. The
fix checks each positional pair's leading numeric section prefix ("2"from"2. Types"/
"2. 型") and raisesSystemExitnaming both headings and the position on a mismatch, needing
no new maintained ja/en heading-name table. That per-position check is only sound if
docs/LANGUAGE.md's own numbers are unique, so a second assertion now rejects a duplicated
English section number directly, naming the duplicate, instead of leaving uniqueness an
unstated precondition. Rejecting controls (a same-count reordering fixture and a duplicate-number
fixture) and an accepting control (the real, untouched files) are all in
tests/test_site_reference_snapshot.py. - Fixed (#757): sharded Rust and semantic-mutation artifacts now use stable logical names so a failed
shard can be rerun without discarding successful peers. Provenance, checksums, shard identity, and
exact-union controls reject incomplete or incompatible mixed-attempt cohorts. - Fixed (#762): restore the native root CLI-help contract formatting while retaining concise summaries for every top-level command.
- Fixed (#786): Prove the native-only
enum abstractionrefinement exclusion by neutralizing only its registered block and reject stale or shadowed registry entries. - Fixed (#795): failed trusted Actions cache-budget audits now maintain one deduplicated issue and close it after recovery.
- Fixed (#818): a compose document with an undeclared component alias inside a
top-levelinitblock'sforallbinder no longer panics past the public
API boundary.rewrite_compose_statementsnow returnsResultand its
caller inlower_composepropagates with?, sofsl_core::parse_kernel_source
returnsErr(CoreError)with the "unknown alias" message instead of the
process aborting. A rejecting control exercises the reproduction through
parse_kernel_source; an accepting control confirms a correctly declared
alias used in aforallbinder still lowers successfully. - Fixed (#821): the explicit-engine init duplicate-write check now rejects a
forall i { m[i] = ... }write that overlaps a later flatm[K] = ...write to the same concrete keyK,
whether or not the two values agree. It previously tracked forall-indexed writes at
whole-variable granularity while flat writes were tracked per key, so an overlapping flat
write with an agreeing value was silently accepted and one with a conflicting value fell
through to the unrelated "init constraints are unsatisfiable" diagnostic instead of the
duplicate-write rule's own message. - Fixed (#822): Offer
usein LSP completion and enforce reasoned parity with rename-validation keywords. - Fixed (#840): Cache-budget audit wiring validation now reports malformed sibling workflows without a traceback.
- Fixed (#843):
fslc testgenno longer bakes a Monitor rollback as a conformance expectation. The
fixed-seed walk is a concrete Monitor run capped at 100 steps and independent of
--depth, so it could reach a violation the bounded verificationtestgenruns
first proved absent withindepth; the violatingStepResultwas discarded and
the rolled-back (unchanged) state was recorded as that step'sexpected. A
conforming implementation failed the generated test, an implementation that
silently did nothing passed it, and--target pytest-- which drives the walk live
-- reached the opposite conclusion from the five baked targets on the same input.
The walk now fails closed, reporting the violation with the same
result:"violated"envelope, exit code, property, step, and replayable trace
verifyreports, and writing no harness. - Fixed (#846): the Rust workspace is clean again under
clippy1.98.0, whose
new deny-by-defaultmanual_is_variant_andandchunks_exact_to_as_chunks
lints turnedmainred with no repository change, because every CI job uses
the unpinneddtolnay/rust-toolchain@stable. Both rewrites are
semantics-preserving. CI named only two sites, since cargo aborts at the first
failing crate; enumerating with--keep-goingfound four, and the fix was
also checked against the pinned 1.88.0 MSRV thatrelease.ymluses so
as_chunkscannot break the release build after PR CI passes on stable. - Fixed (#847): Scheduled and manually dispatched product-gate failures now reconcile through the post-merge CI reporter.
- Fixed (#851): Cache-budget audit workflow-name validation now rejects case-only,
surrounding-whitespace, and compatibility-Unicode collisions with the reporter source. - Fixed (#855): map-key diagnostics now explain when a
constshadows a member of
the map key enum and advise renaming one of the colliding declarations. - Fixed (#856): Replaced workflow line scanners with required PyYAML-backed audits that preserve source diagnostics, reject ambiguous YAML, and pin the privileged post-merge reporter checkout and execution shape.
- Fixed (#857):
rust testsandrust checkshave cold-build margin. A cold
rust testsshard was measured at 30m04s against its 30-minute budget and was
cancelled, turning the aggregaterust workspacerequired context red;
docs/DESIGN-ci.mdhad recorded that outcome as an unobserved risk. The budgets
move to 45 and 30 minutes, sized from measured cold durations (24m59s / 27m12s /
30m04s for the shards, 16m35s forrust checks) against warm baselines of
9-11m and 2m. #747 records why cold builds recur: two concurrent pull requests
exceed the 10 GiB Actions cache ceiling and evict each other, so a budget with
no cold margin turns a routine eviction into a failed required context. - Fixed (#858): the public types that carry a verification outcome are now
#[must_use]on the
type rather than only on the functions returning them.Resultis already
#[must_use], somonitor.step(x).map_err(..)?;satisfied the compiler while the
innerStepResult-- which ownsviolation-- was dropped as a statement value;
annotating the function is redundant againstResultand closed nothing. With the
attribute on the type,cargo clippy -- -D warningsrejects the discard where
the outcome is returned directly, which is the shape behind thetestgenwalk
bug. It does not reach an outcome wrapped inOption:#[must_use]does not
propagate throughOption, andOptionis not itself#[must_use], so a
-> Result<Option<Outcome>, E>signature stays undetectable by this mechanism
(issue #868). - Fixed (#860): recognize integer constants as distinct concrete keys when checking
initcoverage for integer-keyed maps. - Fixed (#861): make the release Linux linkage guard reject binaries dynamically linked to libz3, with accepting and rejecting ldd fixtures. The separate GLIBC behavioral-control finding is tracked in #865.
- Fixed (#862):
Map<Int, V>is rejected at check time in every grammar-reachable type position, preventing verification from materializing an unbounded key domain. - Fixed (#868): Detect discarded optional verification verdicts through direct and source-declared alias return types, and assert expected bounded-liveness observations.
- Fixed (#871): Corrected the release-linkage calibration to name both conditions
behind the former hole:!exempted the failing pipeline fromerrexit, and
the final clean iteration then supplied the loop's status. - Fixed (#873): generated cargo-mutants liveness exclusions now derive their
line-scoped expressions from the maintained source anchors instead of requiring
hand-copied line numbers. - Fixed (#875): causal expectation replay now reports a
within 0liveness
violation found in the initial state instead of returning a falsepass. - Fixed (#882): the generated cargo-mutants configuration's freshness check no longer fails unconditionally on a CRLF checkout.
mutants.tomland its template are pinned to LF via.gitattributesand the comparison normalises line endings, so the gate's verdict does not depend on checkout configuration. Found by the promotion-only Windows solver lane after #880 merged, because that lane is skipped on pull requests. - Fixed (#883): text checkouts are pinned to LF and #858's source-inspection control normalises CRLF reads, so its adjacent-line assertions do not depend on checkout configuration.
- Required (#802): cache-budget audit workflow wiring now has parsed-YAML calibration controls for every validator rejection and diagnostic CLI input failures.
- Required (#812):
mutatenow preserves malformed causal parser diagnostics through an executable error-envelope parity control. - Required (#845): cache-budget audit workflow-name uniqueness now blocks main
merges through merge readiness. - Required (#850): Native CLI regression coverage now detects incorrect failed-link
identities and composed action maps in multi-linkfslc refinechains. - Required (#865): Added accepting and rejecting fixture controls for the Linux
release GLIBC ABI guard. The required product gate now exercises the deployed
guard with compliant GLIBC_2.39 and rejecting GLIBC_2.40 `...
v4.3.0
-
Fixed (#753):
git applysilently skips every file in a patch, and exits zero, when the
fault-operator scratch checkout is not its own git repository root -- git resolves the
scratch to the enclosing repository, where everything under it lives beneathrust/target/
and is git-ignored (Skipped patch '<path>'., exit 0). The scratch then compiled
unfaulted, every detector passed because there was nothing to detect, and the harness
recorded that as a detector gap.sync_scratchguarded this with[ -e "$scratch/.git" ],
which tests the wrong property: an empty or partial.gitfrom a restored CI cache
satisfies it and suppresses the repair, which is why the failure appeared only in CI and
varied run to run. The guard now requiresgit rev-parse --show-toplevelinside the scratch
to equal the scratch, andgit apply --verboseturns aSkipped patchline into a nonzero
status. -
Fixed (#753): the implementation fault-operator harness now witnesses that a fault
reached what it measured instead of inferring it. Aprimary still passed under the faultverdict has two causes with different owners -- the detector does not cover the
seam (a real gap) or the detector never saw the fault (a harness defect) -- and
tools/run-fault-operators.shpreviously reported the first whenever the second was
true, because it treated a zero-exitgit applyplus a clean build as proof of arrival.
The symptom was the same operator returning different verdicts on different runs of one
revision, which made unrelated pull requests unmergeable through thesemantic mutation
required context. Two fail-closed witnesses now run before any verdict: every file a
patch names must differ byte-for-byte from the pristine copy after the patch applies,
and, of the two artifacts a detector can execute -- the test harness binary, read back
from cargo's ownExecutable <target> (<path>)line, and thefslcexecutable a
detector may spawn viaenv!("CARGO_BIN_EXE_fslc")-- at least one must differ from the
digest recorded for it under the no-op control. Both are checked because an operator's
fault normally reaches exactly one: a patch underrust/fslc/tests/**changes the test
binary, a patch underrust/fslc/src/**changesfslc. A byte-identical pair cannot
arise from compilation nondeterminism, so the binary witness fires only on real artifact
reuse.
The source witness carries its own negative control,
rust/fslc/tests/fault_operators/controls/identical-after-apply.patch, a hunk that
applies cleanly while leaving the file unchanged and must be refused; the binary witness
is calibrated by live mutation and has no fixture, recorded as such in
docs/DESIGN-conformance-harness.md. -
Decided (#737): the shared-edit merge-conflict spike closes as GO for CHANGELOG
fragments only (C1) and NO-GO for fragmenting the contract documents (C2), recorded
in the new accepteddocs/DESIGN-changelog-fragments.md. The load-bearing evidence is a
replay of history atd72ac8d: of 22 genuinely concurrent branch pairs (interval overlap
plusgit merge-base --is-ancestorfalse both ways, conflicts detected with
git merge-tree --write-tree), 16 conflict,CHANGELOG.mdis a conflicting file in 16 of
16, and the three current-era conflicts have it as the only conflicting file — while
fragmentingdocs/LANGUAGE.md/docs/LANGUAGE.ja.md/skills/fsl/reference.mdresolves
zero additional pairs (every contract-document conflict co-occurs with an implementation
conflict in one early-Python cluster), which is #737's own no-go condition, and would put
a generated layer upstream of the requiredsite reference freshnesscheck. The record
carries the six fail-closed negative controls (missing or empty fragment, duplicate id,
order determinism plus conformance on both the category and id sort components,
unaggregated-at-release plus bidirectional direct-edit, aggregation conservation against
silent entry drops and against truncation, and fragment-name conformance), each with a
calibrated rejecting fixture and named diagnostic, the six migration sites, the rollback
method, and the reversal condition.<category>follows this repository's bullet
lead-word convention, not Keep a Changelog's: the measured[Unreleased]body has zero
###subheadings and already usesDocumentedandDecided, so the aggregator emits
bullets rather than introducing subheadings. Implementation is deliberately not included. TheLANGUAGE.md/
LANGUAGE.ja.mdsection-alignment enforcement is untouched by C1; a pre-existing
count-only gap in that enforcement found during the evaluation is tracked as #741. -
Documented (#738): the command-family extraction spike's result as re-evaluation evidence in
docs/DESIGN-rust-components.md. Section 10's first trigger — three unrelated command changes
failing onfslcorchestration coupling — has fired (the exit-code chain alone supplies five)
and is adjudicated: the harmful coupling is one contract policy implemented at more than one
site, which a vertical command-family split cannot remove, so further family extraction is
no-go and a new crate is rejected for lack of independent version/dependency/consumer evidence
(C1 remains the selected candidate). The one executed extraction (causal.rs, #393 / PR #440)
produced zero confirming samples and two counter-shaped ones in 13 days — both workspace-wide
refine changes, so the falsifier section 8 already named appeared in shape while the effect
stays unconfirmed, not disproven; the response that measurably worked is policy single-owner
extraction (spec_load.rs,outcome.rs,literate_access.rs): after743bc7agave spec-load
classification one owner,main.rsinvolvement fell 379 → 179 → 16 lines across its follow-up
series. Section 8 records the discriminator the spike leaves behind, and it is stated in terms of
implementation sites, not call sites — one contract policy implemented at more than one site is
harmful coupling; an arm that only calls into a single library owner is cohesion, however many arms
call it. That distinction is the whole rule: counting call sites makes every centralized policy look
coupled, because centralizing is what produces callers, and counting only recurrence misses a policy
whose arms were mismatched from birth, does not capture Case C, and returns both verdicts on a
history where a duplicated policy was later centralized. Touch rate and line count discriminate
nothing (post-extractionmain.rschurn median 29 lines, 26 of 50 commits at wiring scale). The
negative control isc455e50(#697), which the rule rejects: it touchesmain.rs, spans three
crates and changes concrete-verification behaviour, yet its policy —CONCRETE_PROBE_BUDGET
governing the singlefind_boundary_violation— is defined once and merely referenced from four
call sites, with the budget value appearing nowhere else inrust/outside a test comment, an
11-line wiring change inmain.rs, and no later fix landing on a second arm.64bfb55is
explicitly not the control: two of its three defects are multi-site policies, so by this rule it
contains coupling — the rule working, not failing — and two claims made for it are withdrawn, the
single-file pickaxe over a symbol the broken copy never contained, and the false assertion that it
deleted a duplicated hint string (git show 64bfb55^:rust/fslc/src/main.rshas nocoverage_hint
occurrence). Also recorded: the accepting/rejecting controls a future extraction would have to
calibrate, and the measurable changed-owner rollback rule any future extraction PR must carry.
Documentation only; no Rust behavior changed. -
Fixed (#720 Finding 1):
rust-tests'cargo-nextest --partition count:K/3balanced pre-merge
shards by test count, not wall clock, so five binaries holding ~77% of the suite's sequential time
(refine_corpus_parity,explicit_engine,injection_detector_matrix,corpus_check_sweep,
issue_226_auto_engine) could land unevenly across shards — measured spreads of 2.2x and 3.1x
between the fastest and slowest shard on two runs of the same commit, now both
recorded indocs/DESIGN-ci.md(previously only the 2.2x run was).check_rust_testsintools/check-native-integration.shnow
pins those five binaries to specific shards via a checked-in
tools/rust-test-shard-groups.txtandcargo nextest'sbinary_id(=…)filterset, unpartitioned,
while every other test still goes through the original count-partition, scoped to exclude every
pinned binary. Coverage cannot silently drop: an unlisted binary simply falls into the
count-partitioned leftover as before, andtools/check-shard-union.sh's existing full.txt/shard.txt
guard needed no shape change to keep validating the result. Addedcheck-shard-union.sh check-groups, a narrower guard that fails closed if the grouping file pins a binary-id the live
workspace no longer has or pins one binary to two shards, plus new accepting/rejectingselftest
cases (including a whole-binary-dropped fixture) wired into the existingmerge readiness / automation contractslane..github/workflows/ci.ymlis unchanged — the requiredrust workspace
context, itsif: always()aggregator, and the shard-union contract all keep their exact shape.
Measured, and the second form delivers: the slowest shard — the only quantity
rust workspacewaits on — fell from 15.6 min to 12.2 min and the spread from 3.1x to 1.17x
(warm-cache runs 31076668077 and 31081427765 attempt 2; shard wall clocks 12.2 / 10.85 / 10.46 min,
clean shard union on both). The first form delivered ~0.1 min and this entry previously said so;
two measured defects explain the gap. The cost model was wrong twice: packing by each binary's
sequential total, then...
v4.2.0
- Fixed native Rust business-dialect precedence policies so
every <Entity> reaching ... must have passed through ...lowers to deduplicated history
state, transition updates, the attributed no-bypass invariant, and its
dominated-set stability invariant. Native BMC, induction, and explicit-state
regressions now fail if the lowering is hollowed back into a no-op (#681). - Hardened semantic migrations against another hollow accepted construct:
behavior-bearing variants now require executable or fail-closed controls,
the precedence bypass gallery and a curated implementation fault operator
calibrate native detection, all four business policy variants have native
rejecting controls, and both agent harnesses retain soundness findings until
they are fixed or linked to an issue; the merge-readiness automation lane
executes that harness contract on every pull request (#681). - Accepted the measured correlated-saga-history design: retain one-hot event
flags as current-transition observations and add a dedicated
correlation-indexed six-phase saga map in a follow-up. The maintained
two-correlation fixture measures the three candidates as ×1 reused effect
state, 32 sticky-event valuations versus 6 one-hot valuations, and 36
dedicated saga-progress valuations; a negative control proves global sticky
flags alias correlations (#662). - Reached
Seqpop/head/at/index operations are now uniformly
partial_opviolations in property context across Monitor BFS, explicit
verification, native/browser symbolic BMC, and CLI rendering. The contract
includesterminalandleadsTo, so neither can turn an undefined Seq read
into a solver-selected deadlock decision or vacuously false antecedent.
Symbolic phantom slots can no longer fabricate a property verdict or
reachable witness; property-context/and%zero totalization is
unchanged (#650). - Native BMC now distinguishes structurally impossible
reachabletargets
from depth-limited ones.over_constrainedentries carry an irreducible
blocking_requiresset computed in an independent solver session, so path
UNSAT cannot poison the classification and diagnostic queries cannot perturb
native/browser witness projection (#634). - Fixed
fslc typestatesilently omitting locally guarded read/query actions.
They now appear as explicit state-preserving self-loops, and generated
TypeScript preserves the caller's exact phantom state instead of widening a
multi-state guard (#635). - Bounded LSP workspace discovery now scans only direct siblings for a document
opened outside every registered workspace root, preventing an arbitrary
parent such as/tmpfrom becoming an unbounded recursive index while
preserving explicit workspace and sibling cross-file behavior (#623). fslc explaincounterfactual weakening now evaluates only the invariant and
reachable outcomes it actually reports, and explicitly marks liveness as
skipped. QuantifiedleadsTochecks no longer multiply every safety mutant's
runtime while their results are discarded (#633).- Added a calibrated
vacuous_deadlinelane that proves a generated deadline's
age remains zero across every transition, catching state-changing urgent
handlers that evade the narrower globalurgency_freezeproof. The SLA worker
example now consumes slack and fails when its deadline is tightened (#632). - Added the M13 FSL Logic Test (#673): deterministic valid finite models now
carry stable seed/case IDs, a single-case replay command, machine-coupled
generation/dialect/metamorphic inventory, and named concrete-versus-symbolic
agreement edges over verdicts, clean-run reachables/action coverage, exact
witnesses, replay, and successor admission. PR and scheduled tiers emit a
fail-closed completeness report; scheduled evidence spans three seeds and
three depths (1,152 cases), delayed violations carry nontrivial actions, and
a comparator corruption control exercises structural shrinking and minimized replay, while a deduplicated corpus owns
future real disagreements. Generation volume does not promote public
assurance or change product output. - Added the M13 soundness-critical semantic mutation gate (#672). A pinned
cargo-mutants 27.1.0pilot now mutates exact P2 bounded-verification,
witness projection/replay, identity/location, and result-fold decisions;
reviewed semantic operators cover unknown/backend failures, inclusive
depth, witness omissions, replay bypass, and false-success folds that
generic token mutation cannot express. Pull requests run changed-scope
mutants plus every curated control, with the detector package named
explicitly even when a diff selects onlyfsl-verifier; product events run
the complete accepted scope. Survivors, timeouts, stale seams, missing output,
and stale equivalence records fail closed; this calibrates detection power
without promoting any public assurance class or changing product output. - Added CI-internal Triangulated Assurance (#670): a federated, fail-closed
registry now requires one raw observation, two explicitly independent
semantic lineages, all three executable agreement edges, positive/negative
calibration, and honest scope. Initial pilots cover compound native outcome
conservation, symbolic-witness/concrete-replay identity (including
state/step/kind/location corruption controls), and token-based dialect
dispatch across the syntax library, CLI, and LSP. A calibrated common-mode
fault executes a production-classifier substitution for the registered P1
independent observer and declares its shared model lineage; no public
assurance class, JSON field, or exit code changes. - Fixed raw
fsl_verifier::verify_bounded*calls bypassing the automatic
action-context partial-operation check. Symbolic BMC now reports replayable
partial_opevidence for ordered guards, reached action bodies, and
ensures, including selected-property, supplied-state, and nondeterministic
init paths; native CLI and Worker no longer sourcepartial_opfrom their
separate concrete boundary pre-scan (#651). - Fixed
domainsaga lowering so effect-owned outcome events cannot bypass the
effect correlation guard through weaker generated observation actions. Three
observation actions disappear from generated kernels (#640). fslc domain checknow preserves the nested kernel'swarningsand
action_coverage, so vacuity and generated-action coverage diagnostics remain
visible to domain users instead of being dropped by the stable projection
(#641).
v4.1.0
-
Semantic Assurance Matrix slices 2/3 add source-derived
expr(24
Expr+ 4AggregateKindrows),types(9TypeRef+ 3TypeDef
rows), anddialects(all 10frontends!keywords) axes for issue #537
C3. A 25-model deterministic C6 family now checks all evaluator-reachable
expression variants and all type rows across Monitor BFS / explicit / BMC,
with a known-violating paired control for every model, whileCall/Stage,
standalone refinement checks, and the Worker's missing agent path are
recorded with fail-closed evidence. -
rust/fslc/tests/typed_agreement.rsintroduces the C6 typed generative /
metamorphic cross-engine agreement suite (issue #537 C6 slice 1, issue
#648,docs/DESIGN-conformance-harness.md"Typed generative / metamorphic
agreement"): a deterministic structural generator (15 domain-axis models- 4 operation-axis models, no randomness) builds checked
KernelModels
and compares Monitor BFS / explicit / BMC verdicts, replay, and successor
admission, plus seven metamorphic relations (alpha rename, BOM/trivia,
inline-vs-explicit init, disjoint assignment reorder, domain-size
boundary, short-circuit/partial/Euclidean duality, entity/number sugar vs
lowered type) each with a positive test and a negative control. Two
confirmed cross-engine findings are recorded as re-measured, self-retiring
exclusions rather than normalized away:verify_bounded's symbolic Seq
encoding treats an out-of-rangehead()read in property context as
defined with an out-of-bound value instead of undefined (a spurious
violated/invariant, disagreeing with the concrete engines' correct
error); andverify_boundedalone never performs LANGUAGE.md's automatic
"Partial operations" check in action context at all (the CLI's
--engine bmcclassification comes from a separate concrete pre-scan,
find_boundary_violation, not the solver).
- 4 operation-axis models, no randomness) builds checked
-
corpus_expectation_manifest.rsandevidence_corpus_manifest.rsgive every
declaredexamples/gallery/{valid,errors,adversarial}fixture and every
causal/agent/ai_componentevidence-only document exactly one native
owner (issue #645, #537 C4 residual). 12 of ~38 declared gallery fixtures had
never been run by any native test —tests/test_gallery.pywas the only
oracle, and it is frozen-Python, outsidetools/check-native- integration.sh— and nothing walked the corpus for an unregistered
causal/fsl-aidocument. All reproduce their declaredresult/kind/exit
natively; no defect surfaced.corpus_check_sweep.rs's
every_corpus_spec_checks_ok_or_declares_its_errorno longer duplicates the
check-targeted half of that claim, now owned by the new manifest instead.
A sharedrust/fslc/tests/support/mod.rsreplaces the corpus-walk helpers
corpus_check_sweep.rsandrefine_corpus_parity.rseach carried their own
copy of. -
rust/fslc/tests/assurance_matrix.rsintroduces the federated Semantic
Assurance Matrix skeleton (issue #537 C3 slice 1,
docs/DESIGN-assurance-matrix.md): axis modules undertests/assurance/
own their rows (read from existing single-owner registries, never copied)
and declared columns; every(row, column)cell carries a
machine-rechecked citation (path + anchor, re-read from the working tree
each run); blank required cells and stale/fabricated citations fail CI;
negative controls prove both checks can actually fail. Slice 1 axes:
outcome_kind(7 Monitor kinds × Monitor/CLI),violation_kind(12
engine kinds × BMC/induction, #646), andproperties(5 KernelModel
property kinds × BMC/explicit/induction/replay). -
fsl-verifier's free-formViolation.kindstrings (BmcViolation/
InductionCti/RankFailure) are now single-owned in
rust/fsl-verifier/src/violation_kind.rsinstead of scattered string
literals (#646). Reading the emission sites directly (not transcribing
issue #646's own citation list) found 12 live values, not the 9 the issue
named —pending_not_preserved,non_decreasing_helpful_action, and
non_helpful_action_increases_measurehad no exercising fixture anywhere
in the corpus before this change. No emitted JSONviolation_kindvalue
changes by a single byte. Part of #537 C3 slice 1
(docs/DESIGN-assurance-matrix.md). -
The kernel AST projection no longer re-serializes every subtree, and is named
for what it is:python_astis nowkernel_ast_v1(#622).json!calls
serde_json::to_valueon each interpolated operand, and the operands were
already-builtValuechildren, so every level deep-copied the subtree below
it — O(depth) stack and O(n²) time per level, spent inside
recursion::guardrather than around it, which is why #620's guard could not
see it. Nodes are now built withValue::Array(vec![...]). The name was
history, not contract: the tagged-array shape came from the frozen Python
reference, but the shape is now the input tofsl-kernel-ast-v1+sha256, which
two digests hash (approval::spec_digest,
document_digest::spec_digest_from_kernel). Deleting or reshaping it would
drift every approval record already in a user's repository; renaming the
function changes nothing a user can observe. -
PredicateExpander::expand_exprandpublic_kernel::expr_jsonare now
guarded too, bringing the #620 table to ten cycles (#622). Neither was
reachable by the #620 witness, whose depth lived in a refinement mapping; a
second generator that puts the same depth inside aninvariant— the shape
the digests actually project — aborted both immediately.expr_jsonis the
more interesting of the two: it called the already-guardedinfer_typeonce
per level, so the guard ran every level, and the crash still landed in
stacker::_growitself, because the check happens on entry and this frame is
large enough that the stack could fall from above the red zone to below what
growing it costs. A guard on a called function is not a guard on the calling
cycle.fslc check,document claims, andkernelnow complete on a
2000-deep invariant. -
Byte-identity was proven by differential sweep, not self-consistency: the
pre-change and post-change binaries were run over all 211 corpus specs under
document claims,analyze, andtestgen, comparing stdout byte for byte —
633 comparisons, 0 mismatches. The sweep's own control came first and mattered:
run against itself the old binary disagreed with itself on 14 files, because
testgenstamps wall-clockelapsed_s/check_elapsed_sinto its envelope.
Those two keys are blanked; nothing else is normalized. -
tools/run-fault-operators.shno longer measures a previous run's fault.
The scratch checkout shares oneCARGO_TARGET_DIRacross steps, andrsync -a
restores the reverted sources with the worktree's mtimes -- which can be older
than rlibs that an operator step compiled with its patch applied. Cargo then
judged those crates fresh and linked the faulted rlib into the no-op control's
binary, so a warm run reported a detector red for a fault that was no longer
in the source. Everysync_scratchnow touches the files any patch names
(taken from the diffs'+++ b/headers), which puts cargo's mtime comparison
on the side of rebuilding without discarding the rest of the warm cache.
Reproduced deterministically -- cold run green, every warm run red,
cargo clean -p fsl-syntaxgreen again -- and verified by restoring clean
sources into a fault-built scratch: before the fix cargo recompiled nothing
and the rebuilt binary still aborted on the #620 witness (exit 134); after it,
fsl-syntaxrecompiles and the witness exits 0. This is the second
scratch-fidelity defect in this harness after the.gitmarker (#611), and
the first to be caught by the no-op control rather than by inspection --
a harness that trusted its cache would have called the operator calibrated
while measuring the fault itself. -
Recursion over a spec's expression structure now grows the stack instead of
aborting the process (#620). #617 made every platform agree on an 8 MiB
stack; it did not make the recursion bounded, and a generated 160-stage
refinement trio still killedfslcwithhas overflowed its stack— exit
134, no JSON envelope, no exit code the outcome contract could read. The
fix isstacker::maybe_growat each recursion cycle entry, not a depth
limit: a limit would put an arbitrary constant into the language contract
and reject legitimate machine-generated specs, and this class was found by
exactly such a spec. Every current answer is preserved and none is added.
The measurement in #620 named two sites; a debugger's innermost frame only
shows whichever site ran out first, so guarding one exposed the next, six
rounds over. Eight cycles across three crates are now guarded —
SyntaxParser::expression,SyntaxExpr::into_kernel,
SyntaxExpr::render_source,Expr::kernel_ast_v1(fsl-syntax),
elaborate_enum_conversions,infer_type,validate_expression
(fsl-core), andeval(fsl-verifier) — behind one
fsl_syntax::recursion::guardthat owns the red zone and segment size, so a
future site cannot pick its own constants. Six of the eight are
crash-witnessed;render_sourceandinfer_typeare not, and each says so at
its definition together with the N at which it was observed to survive
unguarded, so a reader can tell a measured guard from a speculative one.
refinenow proves a 1000-stage trio (a 2000-long right-nestedifchain)
that previously aborted at 160, andcheck/fmtreturn their ordinary
envelopes on the same file.The invariant is not fully met, and #622 tracks the rest.
Expr::kernel_ast_v1
builds its result withjson!, which callsserde_json::to_valueon each
already-built child and re-serializes the whole subtree — O(depth) stack per
level, inside the guard rather tha...
v4.0.0
Changed
- Pull requests into
mainnow run the complete Linux product evidence —rust workspace
andWASM— instead of deferring it to after the merge. Only the cross-platform
native Z3 4.16matrix (macOS, Windows) stays post-merge underFSL_OPTIMISTIC_CI. The
boundedmerge readinesslane is kept as a sub-minute fail-fast check; adding
--all-targetsto itscargo checkwas tried and reverted after measuring 12m42s in
CI, sincerust workspacenow compiles and runs those targets on the same pull
request. 103 of the repository's 124
integration test files live infslc,fsl-tools,fsl-verifierandfsl-lsp, none of
whichmerge readinessruns, so that evidence only reachedmainpost-merge
(docs/DESIGN-ci.md).
Fixed
fslc ai checknow rejects duplicatedatasetandevaluatordeclaration
names, which the frozen reference has always rejected
(src/fslc/ai_project.py:237-241). Native validated only three of the five
declaration kinds, so a project declaringdataset Sharedtwice exited 0 and
reporteddatasets: ['Shared', 'Shared']. Because adataset Xreference
resolves by name, two declarations sharing one made resolution depend on
declaration order — the false green was silently picking a winner, not merely
echoing a name twice (#571).- Native now emits
kind:"name"for name-resolution failures instead of
collapsing them intosemantics, making every member of the
docs/DESIGN-v1.md§7.2 closed set reachable.duplicate state variable,
duplicate enum member,duplicate def,duplicate parameter in def,
def ... parameter is shadowed by binder, andundefined predicatewere all
reported assemantics, sending an agent following the §8 repair protocol
down the wrong branch.CoreErrorandModelErrornow carry the
classification the frontend already determined, and it survives through
SpecLoadErrorto the one renderer — the same direction as #484, rather than
adding patterns to the message-string classifier, which has no text these
diagnostics share and would silently reclassify them on any wording change.
Messages are byte-identical and no otherkindmoves.
examples/gallery/errors/name_duplicate_state_variable.fslis the corpus
golden the classification never had; its absence is why this survived #484 and
#555. Itslocnow names the redeclaration rather than the first binding:
the diagnostic carried no span of its own, so it fell back to the
message-derived heuristic, which finds the earlierxand pointed a repair
agent at the innocent declaration (#565). - A
duplicate enum memberdiagnostic now points at the repeated member rather
than the first declaration of that name.SpecItem::Enumcarried no
per-member span, so the report fell back tosource_diagnostic's
message-derived heuristic — the first token matching the quoted name — which
for a duplicate is the earlier, innocent declaration by construction. For
enum E { A, B } enum F { B, C }it namedBinE(2:15) instead of the
redeclaration inF(3:12). Alocthat exists but names the wrong construct
is worse than none:docs/DESIGN-v1.mdG2 assumes the position is correct.
SpecItem::Enumnow carriesmember_spanspositionally parallel to
members, the same shapeSpecItem::Structgained in #555 and the same the
domain surface already used, and the diagnostic attaches the offending
member's own span (#576). - The native<->Worker parity corpus's
unsupportedDocumentsexclusions in
rust/fsl-wasm/test-browser.mjsare now self-retiring. The map excluded 32
refinement/agent/causal documents from the comparison and recorded only a
document type, so if the Worker ever gained a verb for one of them the
exclusion would keep suppressing the comparison forever -- the shape that
left #556's divergent path with zero corpus coverage. Each entry now carries
the measured reason it holds, and every excluded document is probed on the
Worker alone: the recorded premise is that the Worker cannot analyze it, and
the day that stops being true the harness fails and names the entry to
remove. The compared-pair count is unchanged at 351 -- no exclusion was
retired and no document newly compared -- and the run now also reports
exclusionProbes. This stays a capability exclusion, not a
tolerated-difference allowlist: the envelopes are still not compared for
these documents and no verdict, location, or exit-code difference is
allowlisted (#568). - The 28
refinement-typed entries inrust/fsl-wasm/test-browser.mjs's
unsupportedDocumentsexclusion map are retired; the compared native<->Worker
parity corpus grows from 359 to 415 cases andexclusionProbesdrops from 32
to 4 (agent + 3 causal only). The exclusion premise was measured stale: #574
gave native and the Worker one shared classifier (kernel_load_error) for a
document whose top level parses but is not Kernel-shaped, socheck/verify
on every refinement document in the corpus now produce byte-identical
semantics/"spec has no state block" envelopes on both surfaces -- the
exclusion was suppressing zero divergence.specs/cart_refines.fslis now
asserted by name to remain a compared parity case, the same way
duplicateWriteCase/governanceErrorCaseare, so a future silent
re-exclusion fails loudly instead of only showing up as a quiet drop in
parityCases.length(#577). - Every parity-corpus exclusion is now checked to have native answer
non-error, before the Worker launches. This closes the blindness that let
the 28 retired entries go stale: #568's probe tests only the Worker side
(result !== "error"), which detects agreement only when native answers
non-error— agreement then forces the Worker non-errortoo. Native
answerederrorfor all 28 refinement documents, so two sides erroring
looked identical whether or not the errors matched, and the probe stayed
green for weeks. Native answers non-errorfor all 4 surviving exclusions
(okfor agent,causal_model_checkedfor the 3 causal), so the cheap
Worker-only probe is sound for them — and the day an exclusion is added
whose native side errors, this assertion names it instead of silently
reverting the corpus to that blind state. Full envelope comparison was
evaluated and rejected: the causal envelope carries noversionsblock, so
validateEnvelopethrows before any comparison, which is a normalizer
rejection rather than a verdict. The assertion runs in the candidate loop
rather than beside the Worker probe because it depends on nothing but
native, turning a ~6-minute failure into a sub-second one (#577). - The browser parity harness no longer embeds a developer's absolute path.
rust/fsl-wasm/test-browser.mjshardcoded one machine's
/Users/<name>/Library/Caches/ms-playwright/chromium_headless_shell-1208/...
Chrome, the only committed line in the repository containing an absolute home
path, whichAGENTS.mdforbids. Playwright installs each build under its own
version directory and has changed the internal layout between them — both
chrome-mac/headless_shelland
chrome-headless-shell-<platform>/chrome-headless-shellexist on a machine
with two builds installed — so the version, the platform directory, and the
binary name are all discovered rather than spelled out, newest build first
(#583). - A dropped or half-open Chrome DevTools Protocol connection no longer hangs
the browser gate forever.cdp()returned a promise that only the message
listener could ever settle, with no timeout and no socketclose/error
handler, so a response that never arrived hung Node indefinitely; the
surroundingfor (attempt < 360)loop is not a bound when a singleawait
inside it never returns. Because the hang left the process to be killed
externally, thefinallythat terminates Chrome and removes the profile
directory never ran: an orphanedchrome-headless-shell(parent gone,
4h13m old) and seven leaked profile directories were measured on one machine,
and an orphan over two hours old blocked a later gate.cdp()now times out
naming the method, and both socketcloseanderrorreject every
outstanding request, so the failure is loud and the cleanup runs (#584). rust/fsl-wasm/web/cases.mjsno longer claims its smoke cases are compared
against native. The native comparison keyed on them (nativeVerdict) was
removed ind30f456when the corpus-wide parity run replaced it, but the
now-unusedimport { cases }intest-browser.mjsand the header comment
promising "the parity comparison stays honest" both survived, so the file
documented a check that no longer existed. The import is removed and the
comment states what is true: these 9 inline sources are Worker smoke cases
checked in the browser against their ownexpected, and the 415-case corpus
comparison supersedes the removed one (#585).- A kernel-stage failure inside a
use ... fromcomponent now reports the
parent'susedeclaration as itsloc, and names the component's own path
and position in the message. The two used to be mixed: the path came from the
parent (source_file) while the line and column came from the component's
parser, socheckon
examples/gallery/errors/semantics_compose_component_parse_failure.fsl
reported…:7:18— and line 7 of that file is a comment. A location in the
wrong file is worse than none, anddocs/DESIGN-v1.mdG2 requires the output
JSON alone to say where the problem is.locis{line, column}with no
filein all five of itsdocs/DESIGN-v1.mdexamples, so it can only mean a
position in the file the envelope is about; theusedeclaration is that
position, and it is also the line to look at first. The message now reads
`component "" failed to parse ( at ::<c...
v3.1.0
Fixed
- Native induction CTIs now emit the documented heuristic
suggested_invariantsfor monotone
scalar and uniformly initialized Map counters without changing the proof verdict; quantified Map
suggestions choose a collision-free binder so the emitted expression remains reusable (#337). - Native induction lemma handling accepts candidates for selected invariant and
transproperties,
proves each candidate without original user properties, then uses and recommends only the first
independently proved candidate excluding each successive CTI (#336). fslc scenariosnow emits the shortest replayable action-coverage trace even
when the covered action reaches a terminal state before the requested depth,
including requirements transitions guarded byBoolinputs (issue #405).fslc mutate --by-requirementnow attributes acceptance and forbidden kills
through explicit requirement annotations on the failed trace declaration
instead of reporting the linked requirement asempty_formalization(issue
#407). Explicit requirement relations are preserved even when their ID equals
a trace-case ID, while synthetic case relations remain excluded. Duplicate
acceptance or forbidden IDs are rejected so attribution is unambiguous.fslc mutatenow adjudicates singleton bound mutants whose empty domain
produces no action instances instead of panicking in bounded verification;
overflowing integer and bound neighbors are omitted (issue #406).- Explicit domain-effect
success_event,failure_event, andtimeout_event
roles now override event-name heuristics, ambiguous cross-role assignments
fail closed, and completion, retry eligibility, Monitor/BFS execution, and
symbolic verification share the same lowered status (issue #409). fslc lintnow classifies businesspolicy/goalsatisfies CTRL-*
operands as control references, recursively expands directory inputs into a
sorted list of unique physical.fslfiles even when operands repeat or alias
one another, and continues to report nested FSL parse errors instead of silently
skipping them (issues #385 and #386).fslc fmtnow preserves canonical hyphenated IDs in business control,
policy, goal, andsatisfiespositions while retaining normal spacing around
arithmetic subtraction (issue #387).docs/LANGUAGE.ja.mdnow carries the Japanese translation of the
"Literate Markdown FSL" subsection added todocs/LANGUAGE.md§7 by the
literate Markdown feature, sodocs/intro/language.ja.htmldocuments the
.mdinput support instead of silently omitting it (issue #346).- Documentation for the depth-4 underspecification probe (
divergent_choice,
unconstrained_effect) now matches the native implementation: a solver-free
explicit-state BFS over the runtime Monitor, not symbolic BMC/Z3.
docs/DESIGN-underspecification.md,docs/DESIGN-analysis.md,
docs/LANGUAGE.md/docs/LANGUAGE.ja.md, andskills/fsl/reference.mdare
corrected; theevidence_basis:"bounded_bmc"schema enum value is retained
unchanged as frozen v0 vocabulary for "backed by a bounded reachability
witness", so no output or schema contract moves (issue #318). - Mutation documentation no longer overstates the score:
kill_rate = killed / (killed + survived)is now defined everywhere as bounded
mutant-set sensitivity — dependent on the operator mix,--max-mutants
cap,--depth, and the verify/acceptance/forbidden/refinement oracle — not
a production defect-detection rate, spec-correctness probability, or
completeness measure. Survivors are documented as a review queue
(equivalent mutants, dead-at-baseline behavior, beyond-depth effects, or
genuine under-constraint) instead of "a place where an invariant is
missing", andempty_formalization/per-requirement kills as observed lower
bounds within the chosen mutant set and depth. Aligned across
docs/LANGUAGE.md,docs/LANGUAGE.ja.md,docs/DESIGN-mutate.md,
README.md,skills/fsl/reference.md, and the generated site reference; a
newrust/fslc/tests/mutation_docs_contract.rsregression keeps the
stronger survivor claim from returning (issue #338).
Changed
- The native installer no longer clones the repository into
~/.fsl. It now
installs an exact-tag, checksummed CLI/LSP pair under the user data directory,
atomically activates the complete payload, safely migrates recognized Python
2.7 links, and rejects binaries whose reported version differs from the
Release tag. Agent Skills are packaged as a checksummed Release asset; the
v3.0.0 compatibility path verifies a pinned tag-archive checksum and extracts
only the six installed skills.
Added
- Causal portfolio ledger (Phase 5, issue #364):
fslc causal ledger model.fsl [--plans ... --evidence ... --lifecycle ... --as-of ...]
integrates claims, validation plans, evidence, and observations into
a per-claim projection with 12 deterministic attention reasons
(validation_plan_missing,current_evidence_missing,
observation_not_directional_support, etc.). New
fsl-causal-validation-plan.v0schema for immutable plan artifacts
with claim pins, design, scope, observation window, measurements,
and opaque external refs. Plan lifecycle reuses
fsl-causal-evidence-lifecycle.v0. CLI envelope:
causal-ledger.v0(inventory 38). Every claim appears regardless of
plan/evidence; retired claims have no attention; output is byte-stable. - Causal observation bridge (Phase 4, issue #360):
fslc causal observe-expectations model.fsl --from-log events.jsonl --mapping log_mapping.fsl --scope scope.json --period-start ... --period-end ...
replays compiled expectations against a production JSONL log using the
solver-freeBoundedLivenessMonitor. Generates per-expectation
fsl-causal-evidence.v0artifacts withdesign: "observational",
support: "inconclusive",assurance: "replay-observed", and matching
lifecycle records. Pass/violated verdicts never change claim
formal_assuranceorcausal_support. Nonconformant logs,
missing scope/period, and mapping failures are fail-closed.
CLI envelope schema:causal-observation.v0(inventory 36). - Causal expectation lowering (Phase 3, issue #323): explicit
expectation
declarations (trigger action or inline predicate, response predicate,
within N clock <name>,derived_from_claim) compile — fail-closed on
missing/foreign clocks, fractional tick conversion, unresolved references,
or non-kernel targets — into ordinaryleadsTo ... within ticksproperties
on the imported spec; action triggers become one-step pulse ghosts that
never change guards.fslc causal verify-expectations model.fsl [--depth K](causal-expectations.v0) reportspass/violatedwith
assurance: "bounded"; pass and violated goldens both hold the central
invariant that the derived claim'sformal_assurancestays"not_run"
and itscausal_supportis untouched —derived_from_claimis
traceability only, and the legacysupportsfield is a parse error. A
generated property is semantically identical to the hand-written pulse
encoding (asserted by test), and there is deliberately still no
causal verifyalias. - Causal evidence plane (Phase 2, issue #322):
fslc causal analyze --evidence artifact.json [--lifecycle chain.json] [--as-of YYYY-MM-DD]validates
fsl-causal-evidence.v0artifacts (closed design/support vocabularies,
claim ID + content-version pins, scope tokens, ISO-8601 periods, canonical
sha256artifact_digest) and independent append-only
fsl-causal-evidence-lifecycle.v0digest chains, fail-closed on
schema/digest/chain violations. A newcausal_evidence_graphprojection
(and thecausal-reviewprofile) overlays a deterministic per-claim
causal_support—untested | supported | challenged | inconclusive | mixed | unsupported_by_current_evidence— counting only artifacts that pin
the current claim version withsubsumesscope, declared freshness, an
active lifecycle, and an observation window at least the claim's minimum
lag; one source lineage is one vote and staleness is judged only against an
explicit--as-ofdate. Sixteen evidence/measurement review findings
(evidence_scope_mismatch,evidence_window_shorter_than_lag,
duplicate_evidence_source,unobserved_mediator,
unsupported_assumption_chain, ...) join the causal-review profile, all
formal_status: "not_a_violation". Evidence never changes a claim's
formal_assurance: "not_run"— the two axes stay orthogonal by contract
and by test. Ships three new schemas underschemas/fslc/causal/, a
digest-stamped example artifact + lifecycle chain under
examples/causal/evidence/, and docs/skills updates. fslc causal check|analyze|diff(Phase 1 of the review-only causal profile,
docs/DESIGN-causal.md): a standalonecausal <Name> { ... }document —
parsed outside the dialect registry via a pre-dispatch sniff, so the frozen
PythonDIALECT_KEYWORDSparity gate does not move — is typed into a
CausalModel(roles, measurement bindings resolved against imported
kernel/business specs, closed scope vocabulary, claim content versions and
theactive|retiredlifecycle, clock mappings, fail-closed well-formedness
diagnostics includingcausal_instantaneous_loopand
causal_unacknowledged_feedback).causal analyzeemits deterministic
causal_graph/causal_timeline/causal_traceability_graph
projections (JSON/Mermaid/DOT; SCC-condensed, Dijkstra-exact earliest
first-pass, upper-bounded latest through feedback, capped representative
paths with truncation metadata) and acausal-reviewprofile with 15
structural/temporal findings, allformal_status: "not_a_violation"with
do_not_assume.causal diffcompares stable claim IDs and content
versions, flags missing version bumps, retired-claim reactivation, and
retired-hy...
v3.0.0
Changed
- Native v3 releases now assemble and validate all four CLI/LSP pairs, checksums,
VSIX, and Kernel bundles before one tag-only publication step. Release actions,
the Rust toolchain, and the VSIX packager are pinned; publication verifies a
remote draft inventory before making it public, and manual dry runs validate
the same assembled unit without publishing it. Native crates and release
builds require Rust 1.88 or newer. - The installer rejects unsupported Intel macOS, pins repository content and
binaries to the same latest Release tag, and stages both checksummed native
binaries before replacing either installed command. Linux artifacts now have
an explicit Ubuntu 24.04 / glibc 2.39 baseline. All native targets build the
vendored Z3 4.16 source so the distributed binaries do not requirelibz3or
z3.dllat runtime. macOS builds use the Clang 17 runner required by Z3 while
retaining a macOS 14 deployment target, and CI timeouts accommodate clean Z3
source builds on every supported runner. - Release distribution checks now run in the authoritative native Rust gate;
the redundant Python-only release workflow test was removed. - Native
fslc verifycache keys now use a build-time implementation fingerprint instead of
hashing the full executable on every invocation, and CLI preparation reuses its validated
KernelModelacross property selection and engine dispatch. Cache schema v2 invalidates old
entries fail-closed while removing the engine-independent fixed cost found in issue #349.
Added
- Documented a rationale convention for preserving a declaration's "why" in
the checked model instead of only in//comments (lexer trivia): use the
existing@kind(id, text?)to classify and explain a declaration in one
line, and the recommended custom namespace@doc.rationale("...")for a
short rationale that isn't a classification. No grammar, IR, or schema
change; multi-sentence narrative keeps living in comments, and generic
annotations are not currently projected through JSON, LSP, or the audit ledger. See
docs/LANGUAGE.md§13.1.2 (mirrored indocs/LANGUAGE.ja.md),
docs/DESIGN-annotations.md, andskills/fsl/reference.md. fslc lintnow enforces a built-in, kind-aware canonical ID policy and accepts
an explicit--project fsl-project.tomloverride. Requirement, acceptance,
forbidden, policy, goal, control, model, and assumption IDs have distinct
default templates; project tables can replace individual kinds while retaining
all other defaults. Results record the resolved policy, invalid configuration
fails closed, zero-padded numeric ID components retain their exact source
spelling through parsing/lowering, and ID findings are deliberately non-machine-applicable so
migratenever guesses cross-artifact renames. Typed@requirementannotations
are the canonical declaration-link syntax; legacy"ID: text"metadata remains
migration input.docs/intro/language.ja.htmlnow renders from a new, section-aligned Japanese
translation,docs/LANGUAGE.ja.md, instead of reusing the Englishdocs/LANGUAGE.md
body verbatim. FSL keywords,fslccommands/flags, diagnostic/result identifiers,
JSON, and fenced code blocks stay untranslated and byte-identical to the English
source; only headings and prose are Japanese.tools/build_site_reference.pyfails
loudly if the two files'##section counts drift out of 1:1 alignment, and page
anchors/SECTION_BLURBSlookups stay keyed off the English heading so cross-page
links are unaffected. This supersedes the earlier "no translation" stance (see
docs/DESIGN-docs-site.mdD7);docs/LANGUAGE.ja.mdnow moves alongside
docs/LANGUAGE.mdunder the "a language feature moves all of its files together"
rule (AGENTS.md).- Literate Markdown FSL:
fslc check,fslc verify, andfslc scenariosnow
accept.mdfiles containing```fslfenced code blocks directly. Lines
outside fsl blocks are blanked in place so that diagnostic positions (line
numbers, columns, counterexample locs) point to the original Markdown
document. Multiple fsl blocks form one compilation unit; files without fsl
fences are rejected with a clear diagnostic. Fence detection follows the
CommonMark grammar (backtick or tilde runs of length >= 3, matched by
character and length), so a non-fsl fence can safely contain a literal
```fslexample. The verify cache key is stable across repeated runs of
the same document (issue #193). fslc-lspis now a native Rust language server backed directly by the authoritative
syntax, core, and analysis implementation. Existing diagnostics, navigation, symbols,
rename, semantic tokens, completion, hover, and code actions no longer require Python;
corpus/index coverage and stdio lifecycle tests run in the Rust workspace (issue #310).- Required product CI now has one Rust-native integration entrypoint covering the workspace,
dependency boundaries, CLI/schema contracts, native/browser agreement, and WASM. The redundant
Python CLI parity job and its frozen-surface exception snapshot are removed; compatibility Python
tests remain explicit manual evidence. FSL source locations, testgen templates, and generated
artifact digests are portable across the supported native runner matrix (issue #307). fslc analyze --projection code_audit --code <path>now maps checked
executable Kernel requirement targets to a closed, language-independent
@fsl.traceannotation convention. Deterministic JSON reports complete,
partial, missing, orphan, and target-mismatch coverage without presenting
structural claims as proof; versioned input/output schemas and a compliant
fixture define the public contract (issue #222).- Replay-trace schema
1.2.0opts into solver-free boundedleadsTo
monitoring over initial, action, and stutter observations. Inclusive deadline
failures carry property/binding/timing evidence; successful output separates
safety from bounded liveness, preserves finite-prefixpending, and names
unchecked unbounded properties. Native BMC and a test-only Python oracle
cross-check the monitor, and positive/overdue NFR fixtures ship in both Public
Kernel release bundles (issue #225). - Replay-trace schema
1.1.0adds explicitaction: nullobservation points.
Equal-state stutters preserve the projected action trace; reported transient
implementation states are nonconformant while unreported intermediates are
outside invariant judgment. Replay now delegates action outcomes, partial
guards, and rollback toMonitor::attempt, with differential fixtures in both
Public Kernel release bundles (issue #224). fslc replay --tracenow consumes the closedreplay-trace.v1external
compiler contract: trace/Kernel versions, exact spec action/parameters,
canonical ticks, complete typed initial and post-action state, and optional
opaque producer timestamps. Typed observation differences return leaf-level
nonconformance while malformed/incomplete contracts fail closed. Positive and
negative goldens plus the schema ship in both Public Kernel release bundles;
legacy action-only arrays/{events}remain an explicit unversioned adapter
(issue #221).fslc lintnow reports edition-aware diagnostics with stable taxonomy,
severity, spans, canonical replacements, and machine applicability.fslc migrateis dry-run by default and--writeatomically applies only a fully
parsed, checked, location-free Public-Kernel-equivalent file set. Shared
formatter edits cover legacy enums/operators and quantifiers; typed metadata,
unambiguous local action correspondences, and implicit defaults use semantic
planners. Unsafe comment movement, branch/duplicate mappings, and invalid
&&are explicit refusals. The native LSP exposes applicable diagnostics
as quick-fix Code Actions (issue #249).fslc fmtnow formats one registered FSL document or stdin to canonical
stdout without mutating it;--checkaccepts multiple paths and reports a
machine-readable 0/1/2 result. A lossless token/trivia tree preserves line
comments, blank lines, raw spelling, spans, and annotation attachment while
domain enum/logical and quantifier legacy forms normalize to accepted
equivalents. Corpus-wide idempotence and location-free semantic round trips
cover every registered dialect; opaque agent bodies and ambiguous
comment-bearing structural rewrites fail at exact spans (issue #248).fslc verify --engine autocomposes the explicit-state and BMC engines:
explicit runs first (faster, and can proveclosure: true) and falls back
transparently to BMC exactly when explicit cannot decide the spec on its
own (an unsupported feature such asleadsToor nondeterministic init, or
unknown_budget). Every result carriesengine: "explicit"/"bmc"naming
whichever engine decided, and a fallback additionally carries
engine_fallback: {from, reason, kind}so a caller can distinguish a
bounded BMC verdict from an unbounded explicit one, and a permanent
unsupported-feature gate from a transient budget one, without parsing
prose.autoshares verdict-cache entries with plain--engine explicit/bmcruns of the same spec — the cache key is always the engine
that actually decided, neverautoitself — and does not change the
default engine or extend to any other subcommand's--engineoption
(Rust-only, issue #226).- Finite quantifiers,
count,sum,unique, andexactlyOnenow share one
Binder/Aggregate IR across typed, range, Set, and Seq domains. Optional
filters use one scope/type-check path; empty aggregates are zero and Seq
duplicates preserve positional multiplicity. Legacy colon quantifiers remain
detectable as non-canonical input, business/requirements KPI declarations
survive as typed metadata projections, and collection aggregates normalize to
exis...
v2.7.0
v2.7.0 — LSP hover, references, completion, and semantic tokens (#97)
v2.6.3
v2.6.3 — propagate bounds overrides into inline implements abstract (…