Repository navigation
·
154 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
- Changed (#1263): a
provedresult fromfslc verify --engine inductionnow
says what the proof does not cover. The step reasons over unbounded integers
and only the base case (BMC to--depth) checks i64 overflow, so a counter
that overflows beyond--depthstaysproved; the envelope now carries
not_covered: ["int_overflow"]whenever an invariant,trans,leadsTo
trigger/goal/measure,terminal, guard, body orensuresuses an operator
that can overflow (+ - * / %, unary-,abs,sum). The test is
syntactic: arithmetic on small bounded values carries it too, and a proof
with no such operator omits the key (never an empty array).--engine explicitchecks overflow concretely and does not carry it. Additive output
only: no verdict, exit code or other field changes, and the envelope schema
documents the key. Migration: none required; a consumer that needs overflow
coverage should treatint_overflowinnot_coveredas "check with
--engine bmc/explicitat a depth that reaches it, or bound the value". - Fixed (#1197): a compose component's
until/unlessis now rewritten like
its other properties: the name is reported asalias.nameand its operands
read the component's own state. Before, a compose using such a component
failed with exit 2 (cannot type identifier), two components declaring the
sameuntilname collided (duplicate property name), and when the compose
declared state with the same name as the component's, the property silently
checked the compose's variable instead. Migration: a compose in that last
shape that reportedverifiedcan now reportviolated(exit 1) for a
component property that does not hold; theuntil/unlessresult keys
change fromUtoalias.U. - Fixed (#1221):
fslc verify --engine inductionno longer reportsproved
for a spec that indexes a finite-keyMapoutside its key domain (for
examplem[cur + 1]oncecurreaches the top key) beyond--depth. The
step's definedness obligation now also asks, for every invariant,leadsTo
trigger/goal,trans, guard, body (reads and indexed assignments) and
reachedensures, whether a state satisfying the proved invariants reaches
such a miss; asatanswer isunknown_ctiwith the new
violation_kind: "key_domain"andinvariant: "_key_domain_<action>"/
"_key_domain_property_<name>". Within depth the base case reports the same
error as BMC and explicit (map index outside finite key domain/
map assignment index outside key domain), so the three engines agree.
Only sites the obligation catalog cannot place inside the key type are
asked; in-domain reads such asforall k: K { m[k] >= 0 }add no query.
Checked i64 overflow is still not part of the step obligation (#1263).
Migration: a spec that wasproved(exit 0) can now beunknown_cti
(exit 1) when an invariant-satisfying state misses the key domain, or
error(exit 2) when the miss is reachable within--depth; guard the
index (requires cur < 5,cur < 5 => m[cur + 1] > 0) or, if the CTI start
is unreachable, add an auxiliary invariant that excludes it. - Fixed (#1239, breaking):
fslc diffno longer reports an OLDforbiddenas
preserved when a NEW guard disables one of its setup steps. NEW then never
runs the final step, so nothing shows that NEW still rejects it; the forbidden
is nowunknown/forbidden_replay_failedwithstep,action, and
detail: "NEW forbidden setup was not enabled", like a NEW setup step that
violates (#1213) and an OLD setup step that is not enabled. Only a NEW final
step that its guard disables preserves the OLD rejection. The same judgment
servesdiff,diff --git, andapproval diff; no other command changes.
Migration: a diff that passed--forbid unknown(or
--forbid forbidden_relaxed,unknown) may now exit 1 — for example, a NEW that
addsrequires amount != 10to the setupwithdraw(10)and drops the
overdraw guard the forbidden checks.--forbid forbidden_relaxedalone still
exits 0 on it (the final step was never run, so it is not a relaxation); list
unknownin the gate to catch it. Fix the forbidden's setup so NEW can run it,
or confirm the change and update the forbidden. Corpus sweep: no self-diff
changes (docs/design/DESIGN-forbidden.md§2.1 and §6). - Fixed (#1241, breaking): a
forbiddenlast step whose argument is not of its
parameter's kind — an enum member or a Bool for anentity,number, or range
parameter (respond(Waiting)orrespond(true)withc: Case,
withdraw(Red)withamount: Amount), or an integer, a Bool, or another
enum's member for an enum parameter — no longer satisfies the forbidden as
bad_call. It is a spec typo that no guard and no implementation boundary
decided, so it is now akind: "forbidden"error (exit 2) withfailed_step,
step,step_results: [],message,wrong_kind_argument
({parameter, value, type}), alocat that step, and a hint. A value of the
right kind outside a declared range staysbad_call(#1212), and one outside a
verify scope stays the #1229 error. One classifier servescheck,verify
(every engine),sweep,chain,scenarios,testgen,mutate,
counterexample export,html,ledger,approval,explain,fslc diff,
and the Worker'scheck/verify;fslc ledgernames the malformed
argument. Migration: such a spec used to passcheck, andscenarios/
testgenemitted a test assertingbad_call; every command that runs the
forbidden gate now exits 2, exceptexplain(exit 0, no witnesses; #1242),
approval create --kind ledger(exit 0, records the ledger listing the
error; #1243), andapproval checkof a ledger record created before
(drifted, exit 0);approval checkof ascenariosorhtmlrecord created
before exits 2. Infslc diffsuch an OLD final step isunknown/
forbidden_replay_failedwhere it was preserved, and an OLDbad_callwhose
argument NEW's parameter type makes a wrong kind isunknown/
forbidden_step_unrelatable. Fix the step to a value of the parameter's type.
Corpus sweep: no corpus forbidden changes (docs/design/DESIGN-forbidden.md
§2.1 and §6). - Fixed (#1250, #1301): every native
fslcsubcommand now accepts its options before, between, or after its positionals, as the--helpusage lines (rust/fslc/cli-contract.json) and the frozen Python CLI already did.fslc verify --depth 3 spec.fslno longer fails withunknown verify option '3',fslc check --no-cache spec.fslis ausageerror instead of anioerror about a file named--no-cache, andfslc refine --depth 3 impl abs mapruns the refinement instead of returning anioerror with emptychainentries. A value-taking option always consumes its value, and a trailing value-taking option with no value or an unknown option stays ausageerror (exit 2). The spec-first order is unchanged. Migration: a bare--now ends option parsing (argparse semantics), sofslc verify -- -odd.fslnames a spec that starts with-. Such a token without--is now read as an option, so it is reported as an unknown option instead of being opened as a file.fslc analyze --focus,--profile, and--exportwith no value are nowusageerrors instead of being silently ignored. Option errors are reported before spec-loading errors, and an unknownapproval,document,ai, ordomainsubcommand is reported as such even when no spec follows. - Fixed (#1252):
fslc verify --instancesnow reaches the abstract side of an
inlineimplementswhose abstract is arequirementsspec declaring only a
process(noentityof that name). The override was dropped for it, so a
shrunken impl was compared with the full-size abstract and failed with a
falserefinement_failed/map_out_of_bounds(exit 1). No migration is
needed: runs that failed this way now report the seam's real verdict. - Fixed (#1254): a compose sync action now substitutes its arguments into the
component action with capture-avoiding scoping. A statementforall's
whereand range bounds are substituted (they used to reach the Kernel with
the unbound parameter name, exit 2), its binding shadows a same-named
parameter (exit 2 on write-index distinctness before), and neither a
forallbinding nor aletcaptures an argument or sync parameter spelled
like it. Migration: a compose whose sync argument shared a name with a
component'sforall/letbinding, or whosewhereread a compose state
variable named like the component parameter, could reportverifiedfor an
action that breaks the component's invariant; it now reportsviolated
(exit 1). - Fixed (#1259):
x is some(v)whosevrepeats a state variable could make
bmc and induction disagree with explicit-state: the symbolic engines boundv
to the absent payload even whenxwasnone, sop is some(exact) or exact <= 2
wasviolated(or "undefined") under bmc/induction andprovedunder
explicit.checknow rejects a pattern variable that repeats a name already
in scope — a state variable, constant, enum member, action parameter,
quantifier binder,let, or an earlier pattern binding (#1157 item 1) — as a
located semantics error (exit 2), and the symbolicis somekeeps the outer
meaning of the name where the operand is absent, matching the concrete
evaluator. Migration: a spec that used such a collision now failscheckand
everyverifywith exit 2 andpattern binding '<v>' ... rename the pattern variable; rename the pattern variable to a fresh name. No spec in this
repository's corpus is affected. The frozen Python reference still accepts
the collision atcheck. - Fixed (#1275):
preserve progressinside an inlineimplements { }block is
now rejected instead of being accepted and silently unchecked. The inline
seam checks safety refinement only, socheck/verifyused to report
implements.result: "refines"(exit 0) for a mapping whose progress the
standalonefslc refinereports asprogress_lost. Every command that loads
the document (check,verify,scenarios,chain, the LSP, the WASM
Worker) now fails with a locatedkind: "parse"error (exit 2) at the
preservekeyword. Migration: a requirements spec withpreserve progress
in itsimplementsblock now exits 2; delete that item from the block, put
the mapping and itspreserve progressin a standalonerefinementfile,
and runfslc refine <impl> <abs> <refinement>to check the upperleadsTo.
Inlineimplementsblocks withoutpreserve progressare unchanged. - Fixed (#1297): a compose-level
leadsTo,until, orunlesscan now read
component state throughalias.var, as compose-levelinvariant,trans,
andreachablealready could. Before, every such compose stopped with exit 2
(public Kernel cannot type identifier 'a'); it now gets a verdict. No
migration is needed beyond expecting a verdict (includingviolated, exit 1)
where the error used to be. - Fixed (#1314):
fslc scenariosnow folds governancepreservation
results and an inlineimplementsseam into its envelope exactly asfslc verifydoes, through the same mapping (#1303). Before this it answered from
its own bounded run without reading either one, so a document whose
preservation or seam failed gotresult:"scenarios"/ exit 0; only when its
own kernel failed did it fall back to theverifyenvelope, which carried
them. A governance document never takes that fallback, so its preservations
were never read. Now a failing preservation or seam makes the top-level
resultthe folded verdict (refinement_failed,impl_violated, or
unknown_budget, exit 1), every run attaches thegovernance/implements
sectionverifyattaches (also when everythingrefines), and a governance
contract error or inlineimplementserror thatverifyreports is the
same locatederror(exit 2).fslc approval create --kind scenariosreads
the same envelope. Migration: this changesscenariosexit codes and output
for governance documents and requirements documents with an inline
implements, and nothing else. In this repository's corpus, exit 0 → 1:
examples/refinement_liveness/governance_detects_safety_loss.fsl,
tests/fixtures/chain/requirements_broken_implements.fsl, and four test
fixtures; exit 0 → 2: the three governance error examples under
examples/gallery/and two test fixtures; every other governance or
inline-implementsdocument stays exit 0 and gains the section. Fix the
preservation or seam, or, to keep it advisory, run it as a separatefslc refinestep. Ascenariosapproval of such a document no longer matches its
recorded artifact digest (fslc approval checkreportsdrifted, exit 0);
re-approve it.testgen,explain,testplan,diff,analyze, and
kernelare unchanged. - Fixed (#1316):
fslc ledgeron a governance document now states, in its
Markdown body, the verdict its exit code reflects. A new## governance preservationsection, between the header and the risk list, gives the
top-level verdict (検証判定, theverifyresult after the #1303 fold) and
everypreservationin declaration order with itsbefore→after, the
controls it preserves, and its ownresult, 🟢 forrefinesand 🔴 for
anything else. Before this, a failing preservation madefslc ledgerexit 1
while the body showed neither the verdict nor any preservation result, so a
reader of the ledger alone saw no reason for the failure. Migration: only
ledgers of governance documents change; every other ledger is byte-identical.
A governance-document ledger approved withfslc approval create --kind ledgerbefore this release no longer matches its recorded artifact digest,
sofslc approval checkreports itdrifted(exit 0); review the new
section and re-approve it. - Fixed (#1353): an unlocated diagnostic after non-ASCII text on its line (for example an
undefined predicateafter a Japanese invariant title) no longer crashes the language server: its fallback span was a character column used as a byte offset. CRLF line ends no longer shift it either, and the structural-finding location fallback reports UTF-16 positions. No migration is needed. - Documented (#1361): the distributed FSL skills no longer contradict the parser or
each other.numberis documented as requirements/kernel-only (abusiness
spec that declares one is a parse error);if c then a else bis valid in any
expression position; requirementsterminalusesstage(c);@requirement
and@undecidedare the taught tag forms (the"ID: text"slot is
legacy_string_metadata); a kernel spec cannot declareacceptanceor
forbidden; thedecreases-inside-foralldiagnostic is quoted as the
parser emits it; the AI-project examples show only the lines the scanner
reads; broken§cross-references now name the file. Release and issue history that no longer changes what a reader does
("before #1229", "used to", "(issue #N)") was removed from the references;
the current rule is kept. The skills no longer point at repository-only paths (examples/,
docs/,specs/,schemas/) that a mise or install.sh user does not
have; the needed gist is stated in the skill instead. The business, requirements, and design check loops now includefslc lint, and--requirementsis taught as a file of IDs (one per line), not a
comma list. Theexamples/e2eIDs follow the built-in ID policy (POL-EXPENSE-001,
REQ-EXPENSE-001,AC-EXPENSE-001,MODEL-EXPENSE-001, ...): the business
and requirements layers are lint-clean, and every verdict is unchanged.
A new distributed skill,fsl-verify, owns verification. It
gives the command sequence per layer and change kind (check --strict-tags --requirements→lint→verify --depth 8→--engine induction→refine/implements.result→diff --forbid→mutate --by-requirement→chain), a table of results that exit 0 or look green
without passing (boundedverified;provedonly at the run's
instances/values;deadlock,no_user_invariants, and
unreferenced_requirementwarnings;unknown_cti,unknown_budget,
not_evaluatedfrom--property,not_run,closure: false;diff
without--forbid;mutatesurvivors), the fix loop that never weakens
the upper layer, prohibited shortcuts (lower depth or scope, deleted
properties, ignore flags or--propertyin the completion run), how to
readkill_rateand--by-requirement, and a fixed completion-report
table with proof classes. The business, requirements, design, and
delivery skills keep their minimal check loop and point to it.