diff --git a/.github/styles/config/vocabularies/Custom/accept.txt b/.github/styles/config/vocabularies/Custom/accept.txt
index 3497dd330..4557773a0 100644
--- a/.github/styles/config/vocabularies/Custom/accept.txt
+++ b/.github/styles/config/vocabularies/Custom/accept.txt
@@ -21,5 +21,7 @@ inlined
[Ff]orma(e)?
[Tt]ranspile(d|s|r)?
[Uu]noptimizable
+[Dd]ataiz(e|es|ed|ation)
+[Ss]yscall(s)?
[Cc]yclomatic
[Bb]oolean(s)?
diff --git a/src/main/resources/org/eolang/lints/design/misplaced-dataization.xsl b/src/main/resources/org/eolang/lints/design/misplaced-dataization.xsl
new file mode 100644
index 000000000..a4c6c6b07
--- /dev/null
+++ b/src/main/resources/org/eolang/lints/design/misplaced-dataization.xsl
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ warning
+ true
+ The dataization in
+
+ reads only objects outside of it and runs again in every copy, move it up into
+
+
+
+
+
+
+
diff --git a/src/main/resources/org/eolang/motives/design/misplaced-dataization.md b/src/main/resources/org/eolang/motives/design/misplaced-dataization.md
new file mode 100644
index 000000000..1861f8e00
--- /dev/null
+++ b/src/main/resources/org/eolang/motives/design/misplaced-dataization.md
@@ -0,0 +1,46 @@
+# Misplaced dataization
+
+The cache of a `!` lives in the formation that holds it. When a nested
+formation dataizes an object of the formation around it, every copy of the
+nested formation starts with an empty cache and dataizes the same object
+again. A recursive formation makes a new copy on every step, so the
+delimiter below is dataized once per step, though it never changes:
+
+```eo
+[^ items] > joined
+ [^ acc tup] >> with-delimiter
+ if. > @
+ tup.length.eq 0
+ acc
+ ^.with-delimiter
+ concat.
+ concat. (dataized tup.head) ^.^!
+ acc
+ tup.tail
+```
+
+The lint warns when two things hold. First, the target of a `!` or of a
+`dataized` is a plain chain of attribute reads that goes through `^`.
+Second, the formation that holds it sits inside another formation of the
+same file. Move the dataization up into the enclosing formation, where it
+runs once per call:
+
+```eo
+[^ items] > joined
+ ^ >> delimiter!
+ [^ acc tup] >> with-delimiter
+ if. > @
+ tup.length.eq 0
+ acc
+ ^.with-delimiter
+ concat.
+ concat. (dataized tup.head) ^.delimiter
+ acc
+ tup.tail
+```
+
+The lint stays silent on an application, such as `^.sys.accept >>!` with
+its arguments, because a syscall must run on every call, and moving it up
+would run it only once. It also stays silent on a global, such as `eol!`,
+on a top-level formation, whose enclosing object lives in another file,
+and inside a test.
diff --git a/src/test/java/matchers/GrammarMatcher.java b/src/test/java/matchers/GrammarMatcher.java
index bcc5c57a6..7f810f32b 100644
--- a/src/test/java/matchers/GrammarMatcher.java
+++ b/src/test/java/matchers/GrammarMatcher.java
@@ -53,7 +53,8 @@ public boolean matches(final Object obj) {
if (rule instanceof SpellingCheckRule) {
((SpellingCheckRule) rule).addIgnoreTokens(
Arrays.asList(
- "decoratee", "eolang", "spdx", "SPDX-compliant", "Unlinting", "cyclomatic"
+ "dataization", "decoratee", "eolang", "spdx", "SPDX-compliant",
+ "Unlinting", "cyclomatic"
)
);
}
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-a-syscall-on-outer-objects.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-a-syscall-on-outer-objects.yaml
new file mode 100644
index 000000000..612c466ef
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-a-syscall-on-outer-objects.yaml
@@ -0,0 +1,13 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+defects: 0
+input: |
+ [] > server
+ [^ scope] > accept
+ as-number. > client
+ ^.sys.accept >>!
+ ^.sd
+ ^.sockaddr
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-an-application-with-literal-arguments.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-an-application-with-literal-arguments.yaml
new file mode 100644
index 000000000..0a8a647cb
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-an-application-with-literal-arguments.yaml
@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+defects: 0
+input: |
+ [] > counter
+ [^ n] > bump
+ ^.n.plus 1 > next!
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-test.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-test.yaml
new file mode 100644
index 000000000..c8b5e067f
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-test.yaml
@@ -0,0 +1,14 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+defects: 0
+input: |
+ [] > foo
+ 42 > bar
+
+ [] +> reads-bar-once
+ eq. > @
+ ^.bar!
+ 42
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-top-level-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-top-level-formation.yaml
new file mode 100644
index 000000000..06f8bf446
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-top-level-formation.yaml
@@ -0,0 +1,11 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+defects: 0
+input: |
+ [^ substring] > contains
+ ^ >> txt!
+ ^.as-bytes >> mine!
+ txt.eq substring > @
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-moved-up-into-the-outer-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-moved-up-into-the-outer-formation.yaml
new file mode 100644
index 000000000..1482c88dd
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-moved-up-into-the-outer-formation.yaml
@@ -0,0 +1,18 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+defects: 0
+input: |
+ [^ items] > joined
+ ^ >> delimiter!
+ [^ acc tup] >> with-delimiter
+ if. > @
+ tup.length.eq 0
+ acc
+ ^.with-delimiter
+ concat.
+ concat. (dataized tup.head) ^.delimiter
+ acc
+ tup.tail
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-a-global.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-a-global.yaml
new file mode 100644
index 000000000..16e2a14ae
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-a-global.yaml
@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+defects: 0
+input: |
+ [] > reader
+ [^ buffer] >> rec
+ buffer.concat eol! > @
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-its-own-void.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-its-own-void.yaml
new file mode 100644
index 000000000..33675cc95
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-its-own-void.yaml
@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+defects: 0
+input: |
+ [] > list
+ [^ head tail] >> walk
+ head.eq tail.length! > @
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataization-in-an-anonymous-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataization-in-an-anonymous-formation.yaml
new file mode 100644
index 000000000..744954f7b
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataization-in-an-anonymous-formation.yaml
@@ -0,0 +1,15 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+# yamllint disable rule:line-length
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+asserts:
+ - /defects[count(defect)=1]/defect[@line='6' and normalize-space()='The dataization in the formation at line 5 reads only objects outside of it and runs again in every copy, move it up into the formation at line 2']
+input: |
+ [] > outer
+ [^] >>
+ reduced > @
+ items
+ [acc x]
+ acc.plus ^.weight! > @
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataized-keyword-on-an-outer-attribute.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataized-keyword-on-an-outer-attribute.yaml
new file mode 100644
index 000000000..d0c2e9677
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataized-keyword-on-an-outer-attribute.yaml
@@ -0,0 +1,13 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+# yamllint disable rule:line-length
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+asserts:
+ - /defects[count(defect)=1]/defect[@line='4' and normalize-space()='The dataization in "step" reads only objects outside of it and runs again in every copy, move it up into "box"']
+input: |
+ [] > box
+ 42 > size
+ [^ i] > step
+ i.lt (dataized ^.size) > @
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-parent-dataized-in-a-recursive-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-parent-dataized-in-a-recursive-formation.yaml
new file mode 100644
index 000000000..b66be17e9
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-parent-dataized-in-a-recursive-formation.yaml
@@ -0,0 +1,19 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+# yamllint disable rule:line-length
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+asserts:
+ - /defects[count(defect)=1]/defect[@line='8' and @severity='warning' and normalize-space()='The dataization in "with-delimiter" reads only objects outside of it and runs again in every copy, move it up into "joined"']
+input: |
+ [^ items] > joined
+ [^ acc tup] >> with-delimiter
+ if. > @
+ tup.length.eq 0
+ acc
+ ^.with-delimiter
+ concat.
+ concat. (dataized tup.head) ^.^!
+ acc
+ tup.tail
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-plain-name-of-an-outer-attribute.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-plain-name-of-an-outer-attribute.yaml
new file mode 100644
index 000000000..ef7a836aa
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-plain-name-of-an-outer-attribute.yaml
@@ -0,0 +1,13 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+# yamllint disable rule:line-length
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+asserts:
+ - /defects[count(defect)=1]/defect[@line='4' and normalize-space()='The dataization in "rolled" reads only objects outside of it and runs again in every copy, move it up into "digest"']
+input: |
+ [^] > digest
+ ^.as-bytes >> raw!
+ [^ acc index] >> rolled
+ index.eq raw.size! > @
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/names-the-nearest-enclosing-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/names-the-nearest-enclosing-formation.yaml
new file mode 100644
index 000000000..f6feaa441
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/names-the-nearest-enclosing-formation.yaml
@@ -0,0 +1,13 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+# yamllint disable rule:line-length
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+asserts:
+ - /defects/defect[normalize-space()='The dataization in "climb" reads only objects outside of it and runs again in every copy, move it up into "node"']
+input: |
+ [] > tree
+ [^ left] > node
+ [^ depth] >> climb
+ depth.lt ^.^.height! > @
diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/prints-context-when-lines-empty.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/prints-context-when-lines-empty.yaml
new file mode 100644
index 000000000..12647e82d
--- /dev/null
+++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/prints-context-when-lines-empty.yaml
@@ -0,0 +1,18 @@
+# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
+# SPDX-License-Identifier: MIT
+---
+sheets:
+ - /org/eolang/lints/design/misplaced-dataization.xsl
+asserts:
+ - /defects[count(defect[@context and @line='0'])=1]
+xml-reason: "parser always emits @line; unreachable via valid parse"
+document: |
+