Skip to content

feat(contracts): state_mutation gets a stated contract — a statement that writes to existing state (#2765, Phase 3) - #2818

Merged
squid-protocol merged 1 commit into
mainfrom
fix/2765-state-mutation-contract
Sep 6, 2026
Merged

feat(contracts): state_mutation gets a stated contract — a statement that writes to existing state (#2765, Phase 3)#2818
squid-protocol merged 1 commit into
mainfrom
fix/2765-state-mutation-contract

Conversation

@squid-protocol

Copy link
Copy Markdown
Owner

Phase 3 of #2812, first family. docs/state_mutation_rule_contract.md is the contract, the corollaries, the fallback family and the 46-language audit; gitgalaxy/standards/signal_contracts.py row state_mutation goes draft -> stated (3 of 68).

The contract

state_mutation matches a statement that writes a new value into state that already exists: a re-assignment (plain, compound or ++), an in-place update of a container or structure, or a write through a mutable cell or reference.

The issue's two candidate sentences were a real choice. The rejected one ("the introduction or use of mutable state") is what rust/kotlin/swift/scala/zig and js/ts implemented and it makes the signal a style measure; every consumer (_calc_state_flux, cognitive load, safety, the cascading-flux pair, the cascading_state_mutation bottleneck) reads the count as behaviour, so the count is behaviour.

Corollaries, each found live: (1) a declaration is not a write, even let mut/var/int x = 5/go := -- and where a language has no declaration syntax the assignment statement is the write; (2) a type or modifier naming mutable state is not a write (IORef Int, AtomicInteger x;, volatile, mutable); (3) a read, bind or cast is not a write (this. rvalues -- 376 hits of this.error( in one TS file -- haskell <-, perl bare shift, cpp &, std::move, payable()); (4) one statement is one hit, and a token another rule owns is not a second signal (dockerfile ENV -> globals; matlab clear, m4 popdef, apex .clear( -> cleanup; UPDATE t SET once; s = append(s, x) once).

What changed

  • 30 rules rewritten on one shared shape: a statement-start + bare-lvalue anchor (a type or let/var in front breaks the match) with a trailing-comma guard for enum members / named arguments, ++/-- touching an operand, and receiver-anchored container mutators. Per-language reasoning is in each rule's # #2765 contract: comment and the doc's audit table.
  • Real-world incidence (language-crucible v1.2.0, code stream): c 10644 -> 6300, cpp 11623 -> 4005, rust 2331 -> 636, typescript 9069 -> 5618, perl 5838 -> 3932, lua 6025 -> 2248, sqlite 35 -> 4, haskell 41 -> 1. dart 764 -> 2052 and abap 48 -> 402 widen: plain assignment had been invisible in both (dart's old arm only matched unspaced x=1; abap's rule had no = at all).
  • Corpus: 21 languages' state_mutation cells move (rosetta_audit.py: 21 regressions, all attributed). Rule-side: haskell a.hs 2->0, dockerfile a 2->0, c a 2->0 / b 3->2, go b 5->2, objective-c 3->2, perl 3->2 & c 1->0, m4 c 2->0, apex c 1->0, matlab c 1->0. Plant-side (authored to the old rules, re-planted as real writes in the corpus PR): cpp, java, javascript, kotlin, rust, scala, swift, typescript, zig, solidity, sqlite, abap; livecode/scheme/tcl carried a third write in the decoy line. The re-blessed corpus verifies 46/46 against this branch.
  • Golden masters blessed from a clean language-crucible v1.2.0 worktree (a second bless from the dirty sibling checkout matched byte for byte). tests/tools/bless_scope.py on the diff: 9,363 per master = 4,323 topological + 5,040 substantive, whose leaf keys are exactly the state signal, its weighted view, Amplified Cascading Flux, and the formulas that read it (State Flux / Cognitive Load / Error & Exception exposure, Structural Magnitude, the race-condition pair). One artifact newly parses: cobol/.../RESPSTR.cpy lost ~500 phantom END-STRING hits and no longer trips the aperture's "Packed Payload Guard".
  • Tests: 11 per-language strict pairs flipped; the three "intentional double-classification" tests the contract retires (dockerfile ENV, m4 popdef, matlab clear) rewritten to assert the contract; one cross-language module tests/extraction/languages/test_state_mutation_contract_2765.py (positives/negatives per language, one-statement-one-hit counts, ReDoS detonation for every rewritten regex). Full suite 7,895 passed; ruff/mypy/dead-key audits clean; signal_contract_audit.py --ci exits 0 with the baseline shrunk by one.

Tooling (the process ask)

Every rule session so far rebuilt the same two scripts; they are now standing tools: tests/tools/rule_probe.py (a rule's incidence and matched lines on both corpora, --json snapshots, --compare emits the audit-table rows) and tests/tools/bless_scope.py (the uncapped golden diff bucketed by section / language / leaf key, plus artifacts that moved between parsed and excluded). The rule-contract-audit skill is rewritten as a command recipe with the parallel legs and the worktree/env pitfalls this session hit.

Deferred, with an issue

python, embedded_python and ruby never count a plain local re-assignment (x = v): narrower than the contract by construction, not red on the corpus, and a population-wide reprice of risk_state_flux for the most-scanned language -- filed as #2817 rather than folded in here.

Cross-repo

Engine merges first. keyword-rosetta branch rebless/gitgalaxy-2765-state-mutation (PR to follow) carries the re-plants, 20 manifest cells, the notes, a new ledger entry state-mutation-contract-2765 and the retirements in batch4-dual-keyword-overlaps; its verify.yml goes green once main carries this PR. bias-history.yml regenerates the chart on merge.

Closes #2765

🤖 Generated with Claude Code

… that writes to existing state (#2765, roadmap Phase 3)

One hit is a statement that writes a new value into state that already exists:
a re-assignment (plain, compound or ++), an in-place container/structure update,
or a write through a mutable cell. Four corollaries, each found live in the
46-language audit: a declaration is not a write (even `let mut`/`var`/`int x = 5`/
go `:=`; languages with no declaration syntax count every assignment); a type or
modifier naming mutable state is not a write (IORef in a signature, AtomicInteger,
volatile, mutable); a read/bind/cast is not a write (`this.` rvalues, haskell `<-`,
perl bare `shift`, cpp `&`, std::move, payable()); one statement is one hit and a
token another rule owns is not a second signal (dockerfile ENV -> globals; matlab
clear, m4 popdef, apex .clear( -> cleanup; UPDATE...SET once).

30 rules rewritten on a shared statement-start + bare-lvalue anchor with a
trailing-comma guard. Real-world corpus incidence: c 10644 -> 6300, cpp 11623 -> 4005,
rust 2331 -> 636, typescript 9069 -> 5618, perl 5838 -> 3932, sqlite 35 -> 4,
haskell 41 -> 1; dart 764 -> 2052 and abap 48 -> 402 widen because plain assignment
had been invisible there. Corpus: 21 languages' state_mutation cells move, every
one attributed in docs/state_mutation_rule_contract.md (label rosetta:rebless-owed;
the keyword-rosetta re-bless branch carries the re-plants).

Golden masters blessed from a clean language-crucible v1.2.0 worktree: 9,363 diffs
per master = 4,323 topological + 5,040 in the state signal, its weighted view, and
the formulas that read it (state_flux, cognitive_load, safety, file mass, the
race-condition pair). One artifact newly parses: cobol RESPSTR.cpy lost ~500
phantom END-STRING hits and no longer trips the aperture's density guard.

Also: tests/tools/rule_probe.py (rule incidence + samples + before/after audit rows,
the harness every rule session had been rewriting), tests/tools/bless_scope.py (the
uncapped golden diff bucketed by section/language/key, plus newly parsed/excluded
artifacts), a single cross-language contract test module, and the rule-contract-audit
skill rewritten as a command recipe.

Deferred with an issue: python/embedded_python/ruby never count a plain re-assignment
(#2817). Sheet row state_mutation: draft -> stated (3 of 68).

Closes #2765

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@squid-protocol squid-protocol added metrics Heuristics, risk exposures, and topological math updates core-engine Modifications to the central physics and parsing engine rosetta:rebless-owed Intentionally moves keyword-rosetta counts; audit warns, corpus re-blesses after merge labels Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

@squid-protocol

Copy link
Copy Markdown
Owner Author

Cross-repo: the corpus re-bless is squid-protocol/keyword-rosetta#79 (branch rebless/gitgalaxy-2765-state-mutation, verified 46/46 against this branch, bias report regenerated at full precision: state_mutation 2 in all 43 comparable languages, risk_state_flux open-defect share 0/45, corpus open-defect share 79 → 62 of 2303). This PR merges first; #79 goes green once main carries it.

@squid-protocol
squid-protocol merged commit 932cddc into main Sep 6, 2026
81 of 83 checks passed
@squid-protocol
squid-protocol deleted the fix/2765-state-mutation-contract branch September 6, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core-engine Modifications to the central physics and parsing engine metrics Heuristics, risk exposures, and topological math updates rosetta:rebless-owed Intentionally moves keyword-rosetta counts; audit warns, corpus re-blesses after merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

state_mutation has no stated contract: three incompatible definitions across 46 languages, and it governs the corpus's two worst metrics

1 participant