fpf-thinking-map 1.3.0__tar.gz → 1.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/PKG-INFO +112 -12
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/README.md +110 -9
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/README.md +15 -6
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/WHY_THIS_EXISTS.md +7 -1
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/state.py +65 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/traversal.py +2 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/verify.py +59 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map.egg-info/PKG-INFO +112 -12
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/pyproject.toml +2 -3
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/LICENSE +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/FPF_AUDIT_RESPONSE.md +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/FPF_FLOOR_MAP.md +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/FPF_SOURCE_TO_CODE_RELATION_AUDIT.md +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/REJECTED_C32_CANDIDATE_SYNTHESIS.md +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/REJECTED_NQD_OEE_CULTURAL_EVOLUTION.md +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/RELATED_WORK_GOFLOW_FPF_SKILL.md +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/SOURCES.md +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/__init__.py +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/examples.py +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/guards.py +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/logic.py +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/primitives.py +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/py.typed +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map.egg-info/SOURCES.txt +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map.egg-info/dependency_links.txt +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map.egg-info/top_level.txt +0 -0
- {fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/setup.cfg +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fpf-thinking-map
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Agentic thinking map — structured reasoning constraints for LLMs with TTL evidence decay, deterministic guards, and propositional logic glue. Compiled from FPF (First Principles Framework).
|
|
5
5
|
Author-email: "prichindel.com" <igareosh@igareosh.com>
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/igareosh/prichindel.com-agentic-thinking-map
|
|
8
8
|
Project-URL: Repository, https://github.com/igareosh/prichindel.com-agentic-thinking-map
|
|
9
9
|
Project-URL: Documentation, https://github.com/igareosh/prichindel.com-agentic-thinking-map#readme
|
|
@@ -12,7 +12,6 @@ Keywords: agentic,thinking-map,llm,reasoning,propositional-logic,evidence-decay,
|
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
16
15
|
Classifier: Operating System :: OS Independent
|
|
17
16
|
Classifier: Programming Language :: Python :: 3
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -27,24 +26,53 @@ Dynamic: license-file
|
|
|
27
26
|
|
|
28
27
|
# prichindel.com Agentic Thinking Map
|
|
29
28
|
|
|
30
|
-
**v1.
|
|
29
|
+
**v1.4.0** — [FPF (First Principles Framework)](https://github.com/ailev/FPF), compiled into a small traversal map for LLM agents.
|
|
31
30
|
|
|
32
|
-
A Python package that gives
|
|
31
|
+
A Python package that gives a model a bounded move board instead of a giant framework to digest at runtime. Instead of rereading a sprawling semantic corpus and improvising from it, the model gets a small JSON slice: what context it is in, what move is open, what evidence is missing, what is risky, and what outcome class applies.
|
|
33
32
|
|
|
34
33
|
**[Visual architecture →](ARCHITECTURE.md)** — module graph, step flowchart, floor map, evidence lifecycle, slice structure, deploy sequence diagram.
|
|
35
34
|
|
|
35
|
+
## Why this exists
|
|
36
|
+
|
|
37
|
+
FPF is valuable, but it is large, clumsy at runtime, and poorly shaped for direct model consumption. A human can read a 51k-line framework, understand its distinctions, and apply them carefully. A model usually does something else: it absorbs the vocabulary, performs the tone of the framework, and still drifts on the actual task.
|
|
38
|
+
|
|
39
|
+
This package exists because the useful part is not making the model sound more scientific. The useful part is compiling the parts of FPF that help operational decisions into something small, explicit, and inspectable. We took what mattered for bounded traversal, left out what would bloat or bias the model, and evolved the result as publishers of a practical library rather than trying to reproduce the whole upstream framework inside another AI mega-system.
|
|
40
|
+
|
|
41
|
+
The goal is simple: give the model enough structure to behave understandably, without building a cage so elaborate that it becomes another source of drift.
|
|
42
|
+
|
|
43
|
+
We do not compete with FPF and we do not need to. FPF stays FPF: broad, ambitious, and useful as a frame. This library is the smaller usable tool for people who want the frame without carrying the whole corpus into every project.
|
|
44
|
+
|
|
36
45
|
## What it does
|
|
37
46
|
|
|
38
|
-
You define a domain as a semantic map
|
|
47
|
+
You define a domain as a semantic map: contexts, roles, gates, evidence, transitions. The model gets a per-move slice, not a theory dump. Deterministic guards handle the hard checks. Propositional logic rules (NOT, AND, OR, XOR, IMPLIES, IFF) provide explicit decision glue between the semantic primitives and the current state.
|
|
48
|
+
|
|
49
|
+
The model's job is not "what does FPF mean?" It is: **given this map and this state, what is the best lawful next move?**
|
|
50
|
+
|
|
51
|
+
In practice this does two useful things:
|
|
52
|
+
|
|
53
|
+
- it reduces unexplained drift by moving state tracking and hard checks out of freeform model reasoning
|
|
54
|
+
- it gives the model simple, understandable outcomes such as `CONTINUE`, `COLLECT_EVIDENCE`, `BRIDGE`, `IDLE`, `ESCALATE`, instead of making it reconstruct its own epistemic condition from scratch
|
|
55
|
+
|
|
56
|
+
This is not a panacea. Models still miss information. They still drift. But with a bounded traversal map, the failure mode becomes much easier to explain: missing evidence, wrong context, blocked move, stale basis, unlicensed bridge. The weirdness gets smaller because the state is smaller.
|
|
57
|
+
|
|
58
|
+
## Provable practical gains
|
|
39
59
|
|
|
40
|
-
The
|
|
60
|
+
The improvements here are intentionally simple and operational:
|
|
61
|
+
|
|
62
|
+
- less random drift, because the agent reads explicit state instead of reconstructing state from prose
|
|
63
|
+
- fewer unlawful moves, because guards and scoped transitions check them before the model improvises
|
|
64
|
+
- clearer failure, because "why blocked" is surfaced directly
|
|
65
|
+
- smaller runtime payload, because the model gets a slice, not a corpus
|
|
66
|
+
- easier debugging, because outcomes are discrete and inspectable
|
|
67
|
+
|
|
68
|
+
That is the whole point: practical gain, not intellectual theater.
|
|
41
69
|
|
|
42
70
|
## Quick start
|
|
43
71
|
|
|
44
72
|
```bash
|
|
45
73
|
# No dependencies. Python 3.12+.
|
|
46
74
|
|
|
47
|
-
# Verify the package (
|
|
75
|
+
# Verify the package (22 checks)
|
|
48
76
|
python -m fpf_thinking_map.verify
|
|
49
77
|
|
|
50
78
|
# Run the deploy decision scenario
|
|
@@ -60,7 +88,7 @@ fpf_thinking_map/
|
|
|
60
88
|
├── guards.py 9 deterministic guards (context, role, gate, evidence, assignment, speech act, readiness)
|
|
61
89
|
├── logic.py 6 logic operators + decision rules + LogicLayer
|
|
62
90
|
├── traversal.py Step engine with 10 lawful outcomes (incl. IDLE, BRIDGE)
|
|
63
|
-
├── verify.py Self-verification harness (
|
|
91
|
+
├── verify.py Self-verification harness (22/22 checks)
|
|
64
92
|
├── examples.py 5 deploy decision scenarios (missing evidence, role conflict, logic glue, truth table)
|
|
65
93
|
├── README.md Full documentation (any-model readable)
|
|
66
94
|
├── SOURCES.md Source attribution (FPF spec + Mitev lectures)
|
|
@@ -76,6 +104,8 @@ fpf_thinking_map/
|
|
|
76
104
|
|
|
77
105
|
This package is built on [ailev/FPF](https://github.com/ailev/FPF) by Anatoly Levenchuk. It is an independent implementation — our own research and code, MIT-licensed, with further development rights.
|
|
78
106
|
|
|
107
|
+
It is not an attempt to "finish" FPF, replace FPF, or repackage the whole corpus for LLM ingestion. It is a selective compilation for agentic traversal.
|
|
108
|
+
|
|
79
109
|
### What we reviewed
|
|
80
110
|
|
|
81
111
|
We cross-checked the following FPF commits (June 2026 precision restoration cluster) against our code:
|
|
@@ -104,6 +134,33 @@ Two FPF pattern families rejected for activation bias — they amplify existing
|
|
|
104
134
|
|
|
105
135
|
**Design rule**: the map evaluates and constrains moves. It does not propose them. Generative, branch-friendly, candidate-multiplying patterns are the opposite of what a per-move guard-constrained thinking map should contain.
|
|
106
136
|
|
|
137
|
+
## Scope and non-goals
|
|
138
|
+
|
|
139
|
+
This library is intentionally small in scope.
|
|
140
|
+
|
|
141
|
+
- It is for bounded, stepwise agent traversal in a defined domain.
|
|
142
|
+
- It is for making model behavior more understandable, not more magical.
|
|
143
|
+
- It is for simple +/- operational decisions in context, not for open-ended idea generation.
|
|
144
|
+
- It is for constraining and instrumenting an agent run, not replacing the model.
|
|
145
|
+
|
|
146
|
+
It is not:
|
|
147
|
+
|
|
148
|
+
- a full semantic ingestion layer for all of FPF
|
|
149
|
+
- a universal reasoning engine
|
|
150
|
+
- a replacement for ordinary application logic or policy code
|
|
151
|
+
- a proof that an LLM will behave correctly just because the map exists
|
|
152
|
+
- Memory-Augmented Generation (MAG) — no embeddings, no vector store, no cross-session retrieval, ever, inside this engine. Rejected deliberately and permanently, not by omission. See below.
|
|
153
|
+
|
|
154
|
+
## What this actually guarantees
|
|
155
|
+
|
|
156
|
+
fpf does not ship better reasoning. It ships **inspectability**: did the agent follow the lawful path, and was evidence honestly reported at the one place that matters — the wire between what the agent actually did and what this library was told.
|
|
157
|
+
|
|
158
|
+
Take the stagnation counter as the concrete case. It bounds repetition — but only if the integration maps one real attempt to one `step()` call, and only adds evidence when something genuinely new was found. Whether that actually catches a real LLM thrashing depends entirely on whether the calling harness wires evidence honestly, not just "a tool returned something." That wiring discipline lives outside this library, in whatever integrates it — an agent loop, an MCP server, application code. fpf can't verify that discipline was followed; it can only guarantee that if it was, repetition is bounded.
|
|
159
|
+
|
|
160
|
+
That boundary is the correct seam, not a gap to apologize for. Judging whether a piece of evidence is actually meaningful is a semantic question, and semantic questions need prompting, an LLM judge, or domain logic to answer — which is exactly where that belongs: outside fpf, at the evidence-wiring layer, not folded into a library whose entire value is staying small and deterministic. If you want semantics and clever prompting, that's the plug-in point.
|
|
161
|
+
|
|
162
|
+
**This is also why Memory-Augmented Generation (MAG) is rejected as fpf's own architecture, deliberately and permanently.** MAG — retrieval, embeddings, cross-session recall — solves a different problem (what did we discuss three sessions ago) than fpf solves (is this move lawful right now), and it needs exactly the dependency profile this library rules out by design. That is a scope boundary, not a verdict on MAG as a technique: a MAG system is a legitimate thing to run *upstream* of fpf. Whatever it retrieves becomes an evidence_id in `RuntimeBinding.current_evidence` like any other — fpf doesn't care how evidence was produced, only whether it's present, fresh, and licensed. Memory belongs at the evidence-wiring layer, alongside every other semantic judgment this library deliberately doesn't make.
|
|
163
|
+
|
|
107
164
|
## Sources
|
|
108
165
|
|
|
109
166
|
- **[FPF (First Principles Framework)](https://github.com/ailev/FPF)** by Anatoly Levenchuk — transdisciplinary specification (~51k lines). We extracted 10 semantic primitives and 9 guard rules. This is a compiled distillation, not a port.
|
|
@@ -111,6 +168,22 @@ Two FPF pattern families rejected for activation bias — they amplify existing
|
|
|
111
168
|
|
|
112
169
|
Full attribution in [SOURCES.md](fpf_thinking_map/SOURCES.md).
|
|
113
170
|
|
|
171
|
+
## Why it works
|
|
172
|
+
|
|
173
|
+
The core advantage is not "more theory." It is less runtime burden.
|
|
174
|
+
|
|
175
|
+
Without a compiled map, the model keeps re-addressing its own run: am I allowed to move, did I already satisfy the gate, am I missing evidence, am I in the wrong context, am I done or blocked? That self-management loop is where a lot of bad agent behavior comes from.
|
|
176
|
+
|
|
177
|
+
This package turns that loop into a small stateful instrument panel. The model sees what can fire, what cannot, and why. That is enough of an operating surface for many practical agent tasks. Not a panacea, not a grand theory of intelligence, just enough window and file-handles for the model to open the right thing without smashing the house.
|
|
178
|
+
|
|
179
|
+
The bottleneck was never raw model capability — it's self-management overhead eating the capability that's already there. Most orgs running these models, at any scale, hit that ceiling: infra and process that never actually asked the model for full capacity, so upgrading the model changes nothing. This library doesn't make the model smarter. It shrinks what the model has to hold in its head at any one step, so whatever capability is actually there gets spent on the real problem instead of on self-management overhead.
|
|
180
|
+
|
|
181
|
+
Clean product truth:
|
|
182
|
+
|
|
183
|
+
- FPF is the frame.
|
|
184
|
+
- This library is the usable tool.
|
|
185
|
+
- It keeps the frame where it helps, removes the bloat where it hurts, and gives agents a small operational board that produces simpler, more provable behavior.
|
|
186
|
+
|
|
114
187
|
## Why v1.1 exists — reasoning about reasoning is the bug
|
|
115
188
|
|
|
116
189
|
When an LLM navigates a multi-step decision, it faces the same sub-questions at every step: "Is my evidence still valid? Am I going in circles? Is there another path? Why am I blocked?" Without structure, the model re-derives these answers from scratch each time — re-reasoning on its own prior reasoning. Each pass costs tokens, drifts from the original question, and eventually the context fills up with the model arguing with itself about whether it already checked something it checked three steps ago.
|
|
@@ -131,6 +204,18 @@ The model's job shrinks from "figure out the entire epistemic state of your own
|
|
|
131
204
|
- **Evidence status in prompt** — the LLM prompt state now includes per-evidence freshness and TTL remaining. The model sees "test_results: 3 steps left" instead of just "test_results: exists." Decisions informed by countdown, not by guessing.
|
|
132
205
|
- **Response contract** — every slice now ends with a `response_contract`: the structured template the model must fill when responding. Pre-filled fields (scope, basis with freshness/TTL, allowed use, not allowed use, modality, canonical terms, audience) come from the computed state. Empty fields (claim, risky aliases) are for the model. This is why all the code exists — so the contract has precomputed, validated values instead of being re-derived by the model from scratch.
|
|
133
206
|
|
|
207
|
+
## v1.3.0 changes
|
|
208
|
+
|
|
209
|
+
- **Bridge crossing is enforced, not just advertised** — `ActiveState.cross_bridge()` / `ThinkingMapTraversal.attempt_bridge()` actually perform a cross-context hop and check `substitution_license` against `risk_level` before mutating state. An unlicensed bridge under `high`/`critical` risk is refused (`ESCALATE`), not silently allowed. Before this, `bridge_options()` was advisory metadata only — the model decided for itself whether a lossy translation was acceptable.
|
|
210
|
+
- **`include_full_state=False`** — `step()` can now ship the scoped `slice()` alone, without the whole board bolted on. Default stays `True`; opt in when the caller already knows its `transition_id` and wants the lean payload.
|
|
211
|
+
- 21/21 self-verification checks (`python -m fpf_thinking_map.verify`), two new: bridge crossing and lean-slice payload shape.
|
|
212
|
+
|
|
213
|
+
## v1.4.0 changes
|
|
214
|
+
|
|
215
|
+
- **Stagnation counter** — `ActiveState.register_visit()` / `visit_count` / `visits_remaining` / `is_stagnant` count consecutive `step()`s at the same `(context, state)` pair with no new evidence gathered; the counter resets the moment the evidence set changes. `visits_remaining` mirrors `ttl_remaining`'s exact shape — a countdown, not a boolean. Surfaced in both `slice()` and `to_llm_prompt_state()` as a `stagnation` block. Pure signal: no new outcome kind, nothing blocks, no restraint added to the model's options. Closes a real blind spot — `MoveTrace` is deliberately last-move-only (no narrative accumulation), so the engine previously had no way to notice "I've revisited this exact state N times with nothing new to show for it."
|
|
216
|
+
- The guarantee is conditional, and the docs say so plainly: this tracks evidence *set membership*, not evidence *meaning*. It bounds repetition only if the integration maps one real attempt to one `step()` call and only adds evidence that's genuinely new — see [What this actually guarantees](#what-this-actually-guarantees).
|
|
217
|
+
- 22/22 self-verification checks, one new: `check_stagnation_counter`.
|
|
218
|
+
|
|
134
219
|
## Design principles
|
|
135
220
|
|
|
136
221
|
- **Only add structure when it changes agentic behavior** — not for source fidelity alone
|
|
@@ -140,10 +225,10 @@ The model's job shrinks from "figure out the entire epistemic state of your own
|
|
|
140
225
|
|
|
141
226
|
## Using as a dependency
|
|
142
227
|
|
|
143
|
-
This package is the
|
|
228
|
+
This package is the compiled map, not a thinking replacement for the model. Denying unlawful moves is only half the job. The bigger half is returning the lawful surface as a small, plain-JSON slice: what can fire, what is missing, what is risky, why a move is blocked, what response shape is expected. That lets the model self-address its own run with simple signals such as `can_fire`, `blockers`, and `outcome.kind` instead of re-reasoning about its state from prose.
|
|
144
229
|
|
|
145
230
|
```bash
|
|
146
|
-
pip install
|
|
231
|
+
pip install fpf-thinking-map
|
|
147
232
|
```
|
|
148
233
|
|
|
149
234
|
```python
|
|
@@ -207,10 +292,25 @@ Built with Claude Code (Anthropic claude-sonnet-4-6). Tested and verified to wor
|
|
|
207
292
|
|
|
208
293
|
This is not a compliance seal. It means: we used these models against this package and they produced correct, usable results. The per-move slice is small enough for mid-tier models. The logic and guard outputs are plain JSON — no special tokenization or prompt format required.
|
|
209
294
|
|
|
295
|
+
## Why release this
|
|
296
|
+
|
|
297
|
+
We release this because it is useful beyond our own stack.
|
|
298
|
+
|
|
299
|
+
- It captures a practical subset of FPF in a form models can actually use.
|
|
300
|
+
- It gives agent builders a small constraint surface instead of another giant AI framework.
|
|
301
|
+
- It helps turn model failure from mystical drift into inspectable state.
|
|
302
|
+
- It stays intentionally narrow, so it can remain legible instead of becoming another overbuilt "agent platform."
|
|
303
|
+
|
|
304
|
+
## Credits
|
|
305
|
+
|
|
306
|
+
- **igareosh** — project direction, scope discipline, practical use-case pressure, and product truth
|
|
307
|
+
- **Claude Code (Anthropic)** — implementation support, library iteration, and earlier release preparation
|
|
308
|
+
- **Codex / OpenAI** — product framing polish, packaging cleanup, verification, and release-readiness work
|
|
309
|
+
|
|
210
310
|
## License
|
|
211
311
|
|
|
212
312
|
MIT. See [LICENSE](LICENSE).
|
|
213
313
|
|
|
214
314
|
---
|
|
215
315
|
|
|
216
|
-
**prichindel.com** — v1.
|
|
316
|
+
**prichindel.com** — v1.4.0 — 2026-07-07
|
|
@@ -1,23 +1,52 @@
|
|
|
1
1
|
# prichindel.com Agentic Thinking Map
|
|
2
2
|
|
|
3
|
-
**v1.
|
|
3
|
+
**v1.4.0** — [FPF (First Principles Framework)](https://github.com/ailev/FPF), compiled into a small traversal map for LLM agents.
|
|
4
4
|
|
|
5
|
-
A Python package that gives
|
|
5
|
+
A Python package that gives a model a bounded move board instead of a giant framework to digest at runtime. Instead of rereading a sprawling semantic corpus and improvising from it, the model gets a small JSON slice: what context it is in, what move is open, what evidence is missing, what is risky, and what outcome class applies.
|
|
6
6
|
|
|
7
7
|
**[Visual architecture →](ARCHITECTURE.md)** — module graph, step flowchart, floor map, evidence lifecycle, slice structure, deploy sequence diagram.
|
|
8
8
|
|
|
9
|
+
## Why this exists
|
|
10
|
+
|
|
11
|
+
FPF is valuable, but it is large, clumsy at runtime, and poorly shaped for direct model consumption. A human can read a 51k-line framework, understand its distinctions, and apply them carefully. A model usually does something else: it absorbs the vocabulary, performs the tone of the framework, and still drifts on the actual task.
|
|
12
|
+
|
|
13
|
+
This package exists because the useful part is not making the model sound more scientific. The useful part is compiling the parts of FPF that help operational decisions into something small, explicit, and inspectable. We took what mattered for bounded traversal, left out what would bloat or bias the model, and evolved the result as publishers of a practical library rather than trying to reproduce the whole upstream framework inside another AI mega-system.
|
|
14
|
+
|
|
15
|
+
The goal is simple: give the model enough structure to behave understandably, without building a cage so elaborate that it becomes another source of drift.
|
|
16
|
+
|
|
17
|
+
We do not compete with FPF and we do not need to. FPF stays FPF: broad, ambitious, and useful as a frame. This library is the smaller usable tool for people who want the frame without carrying the whole corpus into every project.
|
|
18
|
+
|
|
9
19
|
## What it does
|
|
10
20
|
|
|
11
|
-
You define a domain as a semantic map
|
|
21
|
+
You define a domain as a semantic map: contexts, roles, gates, evidence, transitions. The model gets a per-move slice, not a theory dump. Deterministic guards handle the hard checks. Propositional logic rules (NOT, AND, OR, XOR, IMPLIES, IFF) provide explicit decision glue between the semantic primitives and the current state.
|
|
22
|
+
|
|
23
|
+
The model's job is not "what does FPF mean?" It is: **given this map and this state, what is the best lawful next move?**
|
|
24
|
+
|
|
25
|
+
In practice this does two useful things:
|
|
26
|
+
|
|
27
|
+
- it reduces unexplained drift by moving state tracking and hard checks out of freeform model reasoning
|
|
28
|
+
- it gives the model simple, understandable outcomes such as `CONTINUE`, `COLLECT_EVIDENCE`, `BRIDGE`, `IDLE`, `ESCALATE`, instead of making it reconstruct its own epistemic condition from scratch
|
|
29
|
+
|
|
30
|
+
This is not a panacea. Models still miss information. They still drift. But with a bounded traversal map, the failure mode becomes much easier to explain: missing evidence, wrong context, blocked move, stale basis, unlicensed bridge. The weirdness gets smaller because the state is smaller.
|
|
31
|
+
|
|
32
|
+
## Provable practical gains
|
|
12
33
|
|
|
13
|
-
The
|
|
34
|
+
The improvements here are intentionally simple and operational:
|
|
35
|
+
|
|
36
|
+
- less random drift, because the agent reads explicit state instead of reconstructing state from prose
|
|
37
|
+
- fewer unlawful moves, because guards and scoped transitions check them before the model improvises
|
|
38
|
+
- clearer failure, because "why blocked" is surfaced directly
|
|
39
|
+
- smaller runtime payload, because the model gets a slice, not a corpus
|
|
40
|
+
- easier debugging, because outcomes are discrete and inspectable
|
|
41
|
+
|
|
42
|
+
That is the whole point: practical gain, not intellectual theater.
|
|
14
43
|
|
|
15
44
|
## Quick start
|
|
16
45
|
|
|
17
46
|
```bash
|
|
18
47
|
# No dependencies. Python 3.12+.
|
|
19
48
|
|
|
20
|
-
# Verify the package (
|
|
49
|
+
# Verify the package (22 checks)
|
|
21
50
|
python -m fpf_thinking_map.verify
|
|
22
51
|
|
|
23
52
|
# Run the deploy decision scenario
|
|
@@ -33,7 +62,7 @@ fpf_thinking_map/
|
|
|
33
62
|
├── guards.py 9 deterministic guards (context, role, gate, evidence, assignment, speech act, readiness)
|
|
34
63
|
├── logic.py 6 logic operators + decision rules + LogicLayer
|
|
35
64
|
├── traversal.py Step engine with 10 lawful outcomes (incl. IDLE, BRIDGE)
|
|
36
|
-
├── verify.py Self-verification harness (
|
|
65
|
+
├── verify.py Self-verification harness (22/22 checks)
|
|
37
66
|
├── examples.py 5 deploy decision scenarios (missing evidence, role conflict, logic glue, truth table)
|
|
38
67
|
├── README.md Full documentation (any-model readable)
|
|
39
68
|
├── SOURCES.md Source attribution (FPF spec + Mitev lectures)
|
|
@@ -49,6 +78,8 @@ fpf_thinking_map/
|
|
|
49
78
|
|
|
50
79
|
This package is built on [ailev/FPF](https://github.com/ailev/FPF) by Anatoly Levenchuk. It is an independent implementation — our own research and code, MIT-licensed, with further development rights.
|
|
51
80
|
|
|
81
|
+
It is not an attempt to "finish" FPF, replace FPF, or repackage the whole corpus for LLM ingestion. It is a selective compilation for agentic traversal.
|
|
82
|
+
|
|
52
83
|
### What we reviewed
|
|
53
84
|
|
|
54
85
|
We cross-checked the following FPF commits (June 2026 precision restoration cluster) against our code:
|
|
@@ -77,6 +108,33 @@ Two FPF pattern families rejected for activation bias — they amplify existing
|
|
|
77
108
|
|
|
78
109
|
**Design rule**: the map evaluates and constrains moves. It does not propose them. Generative, branch-friendly, candidate-multiplying patterns are the opposite of what a per-move guard-constrained thinking map should contain.
|
|
79
110
|
|
|
111
|
+
## Scope and non-goals
|
|
112
|
+
|
|
113
|
+
This library is intentionally small in scope.
|
|
114
|
+
|
|
115
|
+
- It is for bounded, stepwise agent traversal in a defined domain.
|
|
116
|
+
- It is for making model behavior more understandable, not more magical.
|
|
117
|
+
- It is for simple +/- operational decisions in context, not for open-ended idea generation.
|
|
118
|
+
- It is for constraining and instrumenting an agent run, not replacing the model.
|
|
119
|
+
|
|
120
|
+
It is not:
|
|
121
|
+
|
|
122
|
+
- a full semantic ingestion layer for all of FPF
|
|
123
|
+
- a universal reasoning engine
|
|
124
|
+
- a replacement for ordinary application logic or policy code
|
|
125
|
+
- a proof that an LLM will behave correctly just because the map exists
|
|
126
|
+
- Memory-Augmented Generation (MAG) — no embeddings, no vector store, no cross-session retrieval, ever, inside this engine. Rejected deliberately and permanently, not by omission. See below.
|
|
127
|
+
|
|
128
|
+
## What this actually guarantees
|
|
129
|
+
|
|
130
|
+
fpf does not ship better reasoning. It ships **inspectability**: did the agent follow the lawful path, and was evidence honestly reported at the one place that matters — the wire between what the agent actually did and what this library was told.
|
|
131
|
+
|
|
132
|
+
Take the stagnation counter as the concrete case. It bounds repetition — but only if the integration maps one real attempt to one `step()` call, and only adds evidence when something genuinely new was found. Whether that actually catches a real LLM thrashing depends entirely on whether the calling harness wires evidence honestly, not just "a tool returned something." That wiring discipline lives outside this library, in whatever integrates it — an agent loop, an MCP server, application code. fpf can't verify that discipline was followed; it can only guarantee that if it was, repetition is bounded.
|
|
133
|
+
|
|
134
|
+
That boundary is the correct seam, not a gap to apologize for. Judging whether a piece of evidence is actually meaningful is a semantic question, and semantic questions need prompting, an LLM judge, or domain logic to answer — which is exactly where that belongs: outside fpf, at the evidence-wiring layer, not folded into a library whose entire value is staying small and deterministic. If you want semantics and clever prompting, that's the plug-in point.
|
|
135
|
+
|
|
136
|
+
**This is also why Memory-Augmented Generation (MAG) is rejected as fpf's own architecture, deliberately and permanently.** MAG — retrieval, embeddings, cross-session recall — solves a different problem (what did we discuss three sessions ago) than fpf solves (is this move lawful right now), and it needs exactly the dependency profile this library rules out by design. That is a scope boundary, not a verdict on MAG as a technique: a MAG system is a legitimate thing to run *upstream* of fpf. Whatever it retrieves becomes an evidence_id in `RuntimeBinding.current_evidence` like any other — fpf doesn't care how evidence was produced, only whether it's present, fresh, and licensed. Memory belongs at the evidence-wiring layer, alongside every other semantic judgment this library deliberately doesn't make.
|
|
137
|
+
|
|
80
138
|
## Sources
|
|
81
139
|
|
|
82
140
|
- **[FPF (First Principles Framework)](https://github.com/ailev/FPF)** by Anatoly Levenchuk — transdisciplinary specification (~51k lines). We extracted 10 semantic primitives and 9 guard rules. This is a compiled distillation, not a port.
|
|
@@ -84,6 +142,22 @@ Two FPF pattern families rejected for activation bias — they amplify existing
|
|
|
84
142
|
|
|
85
143
|
Full attribution in [SOURCES.md](fpf_thinking_map/SOURCES.md).
|
|
86
144
|
|
|
145
|
+
## Why it works
|
|
146
|
+
|
|
147
|
+
The core advantage is not "more theory." It is less runtime burden.
|
|
148
|
+
|
|
149
|
+
Without a compiled map, the model keeps re-addressing its own run: am I allowed to move, did I already satisfy the gate, am I missing evidence, am I in the wrong context, am I done or blocked? That self-management loop is where a lot of bad agent behavior comes from.
|
|
150
|
+
|
|
151
|
+
This package turns that loop into a small stateful instrument panel. The model sees what can fire, what cannot, and why. That is enough of an operating surface for many practical agent tasks. Not a panacea, not a grand theory of intelligence, just enough window and file-handles for the model to open the right thing without smashing the house.
|
|
152
|
+
|
|
153
|
+
The bottleneck was never raw model capability — it's self-management overhead eating the capability that's already there. Most orgs running these models, at any scale, hit that ceiling: infra and process that never actually asked the model for full capacity, so upgrading the model changes nothing. This library doesn't make the model smarter. It shrinks what the model has to hold in its head at any one step, so whatever capability is actually there gets spent on the real problem instead of on self-management overhead.
|
|
154
|
+
|
|
155
|
+
Clean product truth:
|
|
156
|
+
|
|
157
|
+
- FPF is the frame.
|
|
158
|
+
- This library is the usable tool.
|
|
159
|
+
- It keeps the frame where it helps, removes the bloat where it hurts, and gives agents a small operational board that produces simpler, more provable behavior.
|
|
160
|
+
|
|
87
161
|
## Why v1.1 exists — reasoning about reasoning is the bug
|
|
88
162
|
|
|
89
163
|
When an LLM navigates a multi-step decision, it faces the same sub-questions at every step: "Is my evidence still valid? Am I going in circles? Is there another path? Why am I blocked?" Without structure, the model re-derives these answers from scratch each time — re-reasoning on its own prior reasoning. Each pass costs tokens, drifts from the original question, and eventually the context fills up with the model arguing with itself about whether it already checked something it checked three steps ago.
|
|
@@ -104,6 +178,18 @@ The model's job shrinks from "figure out the entire epistemic state of your own
|
|
|
104
178
|
- **Evidence status in prompt** — the LLM prompt state now includes per-evidence freshness and TTL remaining. The model sees "test_results: 3 steps left" instead of just "test_results: exists." Decisions informed by countdown, not by guessing.
|
|
105
179
|
- **Response contract** — every slice now ends with a `response_contract`: the structured template the model must fill when responding. Pre-filled fields (scope, basis with freshness/TTL, allowed use, not allowed use, modality, canonical terms, audience) come from the computed state. Empty fields (claim, risky aliases) are for the model. This is why all the code exists — so the contract has precomputed, validated values instead of being re-derived by the model from scratch.
|
|
106
180
|
|
|
181
|
+
## v1.3.0 changes
|
|
182
|
+
|
|
183
|
+
- **Bridge crossing is enforced, not just advertised** — `ActiveState.cross_bridge()` / `ThinkingMapTraversal.attempt_bridge()` actually perform a cross-context hop and check `substitution_license` against `risk_level` before mutating state. An unlicensed bridge under `high`/`critical` risk is refused (`ESCALATE`), not silently allowed. Before this, `bridge_options()` was advisory metadata only — the model decided for itself whether a lossy translation was acceptable.
|
|
184
|
+
- **`include_full_state=False`** — `step()` can now ship the scoped `slice()` alone, without the whole board bolted on. Default stays `True`; opt in when the caller already knows its `transition_id` and wants the lean payload.
|
|
185
|
+
- 21/21 self-verification checks (`python -m fpf_thinking_map.verify`), two new: bridge crossing and lean-slice payload shape.
|
|
186
|
+
|
|
187
|
+
## v1.4.0 changes
|
|
188
|
+
|
|
189
|
+
- **Stagnation counter** — `ActiveState.register_visit()` / `visit_count` / `visits_remaining` / `is_stagnant` count consecutive `step()`s at the same `(context, state)` pair with no new evidence gathered; the counter resets the moment the evidence set changes. `visits_remaining` mirrors `ttl_remaining`'s exact shape — a countdown, not a boolean. Surfaced in both `slice()` and `to_llm_prompt_state()` as a `stagnation` block. Pure signal: no new outcome kind, nothing blocks, no restraint added to the model's options. Closes a real blind spot — `MoveTrace` is deliberately last-move-only (no narrative accumulation), so the engine previously had no way to notice "I've revisited this exact state N times with nothing new to show for it."
|
|
190
|
+
- The guarantee is conditional, and the docs say so plainly: this tracks evidence *set membership*, not evidence *meaning*. It bounds repetition only if the integration maps one real attempt to one `step()` call and only adds evidence that's genuinely new — see [What this actually guarantees](#what-this-actually-guarantees).
|
|
191
|
+
- 22/22 self-verification checks, one new: `check_stagnation_counter`.
|
|
192
|
+
|
|
107
193
|
## Design principles
|
|
108
194
|
|
|
109
195
|
- **Only add structure when it changes agentic behavior** — not for source fidelity alone
|
|
@@ -113,10 +199,10 @@ The model's job shrinks from "figure out the entire epistemic state of your own
|
|
|
113
199
|
|
|
114
200
|
## Using as a dependency
|
|
115
201
|
|
|
116
|
-
This package is the
|
|
202
|
+
This package is the compiled map, not a thinking replacement for the model. Denying unlawful moves is only half the job. The bigger half is returning the lawful surface as a small, plain-JSON slice: what can fire, what is missing, what is risky, why a move is blocked, what response shape is expected. That lets the model self-address its own run with simple signals such as `can_fire`, `blockers`, and `outcome.kind` instead of re-reasoning about its state from prose.
|
|
117
203
|
|
|
118
204
|
```bash
|
|
119
|
-
pip install
|
|
205
|
+
pip install fpf-thinking-map
|
|
120
206
|
```
|
|
121
207
|
|
|
122
208
|
```python
|
|
@@ -180,10 +266,25 @@ Built with Claude Code (Anthropic claude-sonnet-4-6). Tested and verified to wor
|
|
|
180
266
|
|
|
181
267
|
This is not a compliance seal. It means: we used these models against this package and they produced correct, usable results. The per-move slice is small enough for mid-tier models. The logic and guard outputs are plain JSON — no special tokenization or prompt format required.
|
|
182
268
|
|
|
269
|
+
## Why release this
|
|
270
|
+
|
|
271
|
+
We release this because it is useful beyond our own stack.
|
|
272
|
+
|
|
273
|
+
- It captures a practical subset of FPF in a form models can actually use.
|
|
274
|
+
- It gives agent builders a small constraint surface instead of another giant AI framework.
|
|
275
|
+
- It helps turn model failure from mystical drift into inspectable state.
|
|
276
|
+
- It stays intentionally narrow, so it can remain legible instead of becoming another overbuilt "agent platform."
|
|
277
|
+
|
|
278
|
+
## Credits
|
|
279
|
+
|
|
280
|
+
- **igareosh** — project direction, scope discipline, practical use-case pressure, and product truth
|
|
281
|
+
- **Claude Code (Anthropic)** — implementation support, library iteration, and earlier release preparation
|
|
282
|
+
- **Codex / OpenAI** — product framing polish, packaging cleanup, verification, and release-readiness work
|
|
283
|
+
|
|
183
284
|
## License
|
|
184
285
|
|
|
185
286
|
MIT. See [LICENSE](LICENSE).
|
|
186
287
|
|
|
187
288
|
---
|
|
188
289
|
|
|
189
|
-
**prichindel.com** — v1.
|
|
290
|
+
**prichindel.com** — v1.4.0 — 2026-07-07
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# FPF Thinking Map
|
|
2
2
|
|
|
3
|
-
This folder contains a Python package that helps an AI model make decisions step by step. It
|
|
3
|
+
This folder contains a Python package that helps an AI model make bounded decisions step by step. It combines a compiled subset of FPF with basic logic operations from computer science so the model can read a small move board instead of digesting a giant framework at runtime.
|
|
4
4
|
|
|
5
5
|
No external dependencies. Pure Python 3.12+. No pip install needed.
|
|
6
6
|
|
|
@@ -15,6 +15,14 @@ This package gives the model a small, structured board to reason on. The board h
|
|
|
15
15
|
|
|
16
16
|
The model reads the board, then picks from a fixed set of moves: continue, ask, abstain, escalate, collect evidence, etc.
|
|
17
17
|
|
|
18
|
+
The point is not to make the model "more intelligent." The point is to make its behavior smaller, more understandable, and less likely to drift for stupid reasons.
|
|
19
|
+
|
|
20
|
+
## Why this package exists next to FPF
|
|
21
|
+
|
|
22
|
+
FPF is strong material for humans, but too big and too clumsy to hand to a model raw and expect clean operational behavior. A model tends to absorb the vocabulary, imitate the posture of rigor, and still miss the simple thing it needed to do.
|
|
23
|
+
|
|
24
|
+
So we did not port the whole framework. We extracted what was useful for bounded traversal, made it executable, and left out the parts that would inflate runtime payload or trigger open-ended academic-pattern generation. This package is not "FPF but more." It is "the part of FPF that helps agents behave better, compiled into something they can actually use."
|
|
25
|
+
|
|
18
26
|
## Where this comes from
|
|
19
27
|
|
|
20
28
|
Two sources, both real academic material:
|
|
@@ -42,7 +50,7 @@ fpf_thinking_map/
|
|
|
42
50
|
├── guards.py 9 deterministic guards the model cannot break
|
|
43
51
|
├── logic.py 6 logic operators + EvidenceFresh + decision rules
|
|
44
52
|
├── traversal.py Step engine with 10 lawful outcomes (incl. IDLE, BRIDGE)
|
|
45
|
-
├── verify.py Self-test: run it, if
|
|
53
|
+
├── verify.py Self-test: run it, if 21/21 pass, package works
|
|
46
54
|
│
|
|
47
55
|
├── examples.py 5 deploy decision scenarios (all features in action)
|
|
48
56
|
│
|
|
@@ -135,7 +143,7 @@ Output: an Outcome with:
|
|
|
135
143
|
- llm_prompt_state: the JSON the model reads to decide its next move
|
|
136
144
|
```
|
|
137
145
|
|
|
138
|
-
When `transition_id` is given, the model gets a `slice()` — a tiny dict with just the move, its gate, its evidence, and whether it can fire. That is the per-move maneuver board.
|
|
146
|
+
When `transition_id` is given, the model gets a `slice()` — a tiny dict with just the move, its gate, its evidence, and whether it can fire. That is the per-move maneuver board. If the caller wants it, the package can now return that lean slice without bolting the full state back on.
|
|
139
147
|
|
|
140
148
|
## How state works (state.py)
|
|
141
149
|
|
|
@@ -158,7 +166,7 @@ Three objects:
|
|
|
158
166
|
- `slice(transition_id)` — tiny dict for one move
|
|
159
167
|
- `transition_to(transition_id)` — execute a transition (checks context, evidence, and gates)
|
|
160
168
|
|
|
161
|
-
**MoveTrace** — compressed history. Only stores last move, not full history: previous_state, last_transition_id, blockers, evidence_delta.
|
|
169
|
+
**MoveTrace** — compressed history. Only stores last move, not full history: previous_state, last_transition_id, bridge_target, blockers, evidence_delta.
|
|
162
170
|
|
|
163
171
|
## Boundary rules (enforced, not advisory)
|
|
164
172
|
|
|
@@ -174,7 +182,7 @@ These constraints are checked at execution time, not just in the display layer:
|
|
|
174
182
|
```bash
|
|
175
183
|
# From the repo root:
|
|
176
184
|
|
|
177
|
-
# Verify the package works (
|
|
185
|
+
# Verify the package works (21 checks)
|
|
178
186
|
python -m fpf_thinking_map.verify
|
|
179
187
|
|
|
180
188
|
# Run the deploy decision scenario
|
|
@@ -253,9 +261,10 @@ outcome = engine.step(state, transition_id="start_to_reviewed")
|
|
|
253
261
|
|
|
254
262
|
- Not a prompt template or system prompt
|
|
255
263
|
- Not a retrieval/RAG system for FPF text
|
|
256
|
-
- Not a replacement for the full FPF spec
|
|
264
|
+
- Not a replacement for the full FPF spec
|
|
257
265
|
- Not a symbolic AI / expert system (the LLM interprets; logic + guards constrain)
|
|
258
266
|
- Not a framework to build on top of — it is a small self-contained package
|
|
267
|
+
- Not a panacea for agent drift; it reduces and explains drift, it does not eliminate it
|
|
259
268
|
|
|
260
269
|
## Known design decisions
|
|
261
270
|
|
|
@@ -4,6 +4,8 @@ This document explains why this package exists adjacent to the original FPF spec
|
|
|
4
4
|
|
|
5
5
|
This is not a critique of FPF itself. As a human-readable transdisciplinary framework, FPF is strong and well-structured. The problem is not the framework — it is the assumption that a language model can absorb a 51,000-line specification and then apply it the way a human reader would.
|
|
6
6
|
|
|
7
|
+
We are not trying to turn FPF into another giant AI stack. We took what was useful for bounded traversal, compiled it, and kept the result intentionally small. That is the product choice here: publish a practical instrument, not an empire.
|
|
8
|
+
|
|
7
9
|
## The triple tax: what happens when a model reads raw FPF
|
|
8
10
|
|
|
9
11
|
When you give a language model the FPF specification text and ask it to make a decision, three things happen in sequence. Each one costs tokens, time, and accuracy.
|
|
@@ -52,6 +54,8 @@ One pass. No translation. No re-reasoning. The code already did the FPF thinking
|
|
|
52
54
|
|
|
53
55
|
The model's job shrinks from "understand this 51k-line philosophy of reasoning and then apply it" to "read this small JSON, fill in the claim field, pick the next move."
|
|
54
56
|
|
|
57
|
+
That smallness matters. It gives the model a simple operating surface for self-addressing its own run: what can fire, what cannot, what is missing, what is risky, whether it should continue, bridge, idle, or escalate. Not mystical agency. Just enough instrumentation to behave properly.
|
|
58
|
+
|
|
55
59
|
## Three problems with feeding raw FPF to a model
|
|
56
60
|
|
|
57
61
|
### 1. It makes the model re-reason N times
|
|
@@ -87,6 +91,8 @@ FPF as a human-readable specification: strong.
|
|
|
87
91
|
FPF as raw input to a language model: triple tax.
|
|
88
92
|
FPF compiled into a thinking map with precomputed state: what this package does.
|
|
89
93
|
|
|
94
|
+
This is also why we release it publicly. The value is not private magic. The value is that other people building agents can stop overfeeding models with giant conceptual blobs and start giving them smaller, inspectable decision surfaces instead.
|
|
95
|
+
|
|
90
96
|
---
|
|
91
97
|
|
|
92
|
-
prichindel.com | 2026-06
|
|
98
|
+
prichindel.com | 2026-07-06 | v1.3.1
|
|
@@ -187,7 +187,10 @@ class ActiveState:
|
|
|
187
187
|
current_state: str = "initial"
|
|
188
188
|
trace: MoveTrace = field(default_factory=MoveTrace)
|
|
189
189
|
step_count: int = 0
|
|
190
|
+
stagnation_threshold: int = 3
|
|
190
191
|
_evidence_added_at: dict[str, int] = field(default_factory=dict, init=False, repr=False)
|
|
192
|
+
_state_visits: dict[str, int] = field(default_factory=dict, init=False, repr=False)
|
|
193
|
+
_state_visit_evidence: dict[str, frozenset[str]] = field(default_factory=dict, init=False, repr=False)
|
|
191
194
|
|
|
192
195
|
def __post_init__(self) -> None:
|
|
193
196
|
for eid in self.binding.current_evidence:
|
|
@@ -276,6 +279,56 @@ class ActiveState:
|
|
|
276
279
|
added_at = self._evidence_added_at.get(evidence_id, 0)
|
|
277
280
|
return max(0, ttl - (self.step_count - added_at))
|
|
278
281
|
|
|
282
|
+
def _visit_key(self) -> str:
|
|
283
|
+
return f"{self.binding.active_context_id}:{self.current_state}"
|
|
284
|
+
|
|
285
|
+
def register_visit(self) -> int:
|
|
286
|
+
"""#28: count consecutive step()s at this (context, state) pair.
|
|
287
|
+
|
|
288
|
+
A revisit with the same evidence set is not progress — it's the
|
|
289
|
+
countable, deterministic version of "the agent is stuck," instead
|
|
290
|
+
of asking the model to introspect about its own psychology. New
|
|
291
|
+
evidence resets the counter: different evidence means there's
|
|
292
|
+
something new to try, not a loop.
|
|
293
|
+
|
|
294
|
+
Called once per step() — see traversal.py. Returns the new count.
|
|
295
|
+
|
|
296
|
+
Syntactic, not semantic: this tracks set membership on evidence_ids,
|
|
297
|
+
not whether anything meaningful actually happened. Two consequences
|
|
298
|
+
a caller should know about. (1) A harness that adds a new evidence_id
|
|
299
|
+
on every attempt — even a low-value one — resets the counter every
|
|
300
|
+
time and this will never fire, no matter how unproductive the loop
|
|
301
|
+
actually is. (2) This only sees what reaches step(); flailing that
|
|
302
|
+
happens inside a single turn and never gets reported back as a step()
|
|
303
|
+
call is invisible to it. The guarantee this method gives is
|
|
304
|
+
conditional: if one real attempt maps to one step() call, and
|
|
305
|
+
evidence is only added when it's genuinely new, revisits are bounded
|
|
306
|
+
at stagnation_threshold. It cannot judge whether an attempt was real
|
|
307
|
+
progress — that's a semantic question this library doesn't answer.
|
|
308
|
+
"""
|
|
309
|
+
key = self._visit_key()
|
|
310
|
+
snapshot = frozenset(self.available_evidence_ids)
|
|
311
|
+
if self._state_visit_evidence.get(key) != snapshot:
|
|
312
|
+
self._state_visits[key] = 0
|
|
313
|
+
self._state_visit_evidence[key] = snapshot
|
|
314
|
+
self._state_visits[key] = self._state_visits.get(key, 0) + 1
|
|
315
|
+
return self._state_visits[key]
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def visit_count(self) -> int:
|
|
319
|
+
"""How many consecutive step()s have landed on this (context, state)
|
|
320
|
+
with the current evidence set, without advancing."""
|
|
321
|
+
return self._state_visits.get(self._visit_key(), 0)
|
|
322
|
+
|
|
323
|
+
@property
|
|
324
|
+
def visits_remaining(self) -> int:
|
|
325
|
+
"""Countdown to stagnation_threshold — mirrors ttl_remaining's shape."""
|
|
326
|
+
return max(0, self.stagnation_threshold - self.visit_count)
|
|
327
|
+
|
|
328
|
+
@property
|
|
329
|
+
def is_stagnant(self) -> bool:
|
|
330
|
+
return self.visit_count >= self.stagnation_threshold
|
|
331
|
+
|
|
279
332
|
@property
|
|
280
333
|
def possible_transitions(self) -> list[TransitionPrimitive]:
|
|
281
334
|
"""#1: scoped to active context + current state."""
|
|
@@ -524,6 +577,12 @@ class ActiveState:
|
|
|
524
577
|
],
|
|
525
578
|
"can_fire": can_fire,
|
|
526
579
|
"blockers": blockers,
|
|
580
|
+
"stagnation": {
|
|
581
|
+
"visits": self.visit_count,
|
|
582
|
+
"remaining": self.visits_remaining,
|
|
583
|
+
"threshold": self.stagnation_threshold,
|
|
584
|
+
"is_stagnant": self.is_stagnant,
|
|
585
|
+
},
|
|
527
586
|
"response_contract": self.response_contract(transition_id),
|
|
528
587
|
}
|
|
529
588
|
|
|
@@ -577,6 +636,12 @@ class ActiveState:
|
|
|
577
636
|
"available_tools": self.binding.available_tools,
|
|
578
637
|
"audience": self.binding.audience,
|
|
579
638
|
"step_count": self.step_count,
|
|
639
|
+
"stagnation": {
|
|
640
|
+
"visits": self.visit_count,
|
|
641
|
+
"remaining": self.visits_remaining,
|
|
642
|
+
"threshold": self.stagnation_threshold,
|
|
643
|
+
"is_stagnant": self.is_stagnant,
|
|
644
|
+
},
|
|
580
645
|
"trace": {
|
|
581
646
|
"previous_state": self.trace.previous_state,
|
|
582
647
|
"last_transition": self.trace.last_transition_id,
|
|
@@ -596,6 +596,64 @@ def check_ttl_decay():
|
|
|
596
596
|
assert s3.effective_freshness("fast_ev") == Freshness.STALE
|
|
597
597
|
|
|
598
598
|
|
|
599
|
+
def check_stagnation_counter():
|
|
600
|
+
"""#28: visit counter + countdown for repeated (context, state) with no new evidence."""
|
|
601
|
+
sm = SemanticMap()
|
|
602
|
+
sm.register_context(ContextPrimitive("ctx", "Test"))
|
|
603
|
+
sm.register_transition(TransitionPrimitive(
|
|
604
|
+
"t1", "Go", "ctx", "stuck", "done", required_evidence=["missing_ev"],
|
|
605
|
+
))
|
|
606
|
+
|
|
607
|
+
b = RuntimeBinding(active_context_id="ctx")
|
|
608
|
+
engine = ThinkingMapTraversal(sm)
|
|
609
|
+
s = engine.build_active_state(b, current_state="stuck")
|
|
610
|
+
|
|
611
|
+
# First visit: 1 visit registered, threshold default 3, 2 remaining, not stagnant
|
|
612
|
+
o1 = engine.step(s)
|
|
613
|
+
st1 = o1.llm_prompt_state["stagnation"]
|
|
614
|
+
assert st1["visits"] == 1, st1
|
|
615
|
+
assert st1["remaining"] == 2, st1
|
|
616
|
+
assert st1["threshold"] == 3
|
|
617
|
+
assert st1["is_stagnant"] is False
|
|
618
|
+
|
|
619
|
+
# Same state, same (empty) evidence, no progress — counter climbs
|
|
620
|
+
o2 = engine.step(s)
|
|
621
|
+
o3 = engine.step(s)
|
|
622
|
+
st3 = o3.llm_prompt_state["stagnation"]
|
|
623
|
+
assert st3["visits"] == 3, st3
|
|
624
|
+
assert st3["remaining"] == 0, st3
|
|
625
|
+
assert st3["is_stagnant"] is True
|
|
626
|
+
|
|
627
|
+
# New evidence arrives — counter resets, this is not a loop anymore
|
|
628
|
+
s.add_evidence("missing_ev")
|
|
629
|
+
o4 = engine.step(s)
|
|
630
|
+
st4 = o4.llm_prompt_state["stagnation"]
|
|
631
|
+
assert st4["visits"] == 1, "new evidence must reset the stagnation counter"
|
|
632
|
+
assert st4["is_stagnant"] is False
|
|
633
|
+
|
|
634
|
+
# slice() carries the same signal for a transition-focused call
|
|
635
|
+
s2 = engine.build_active_state(RuntimeBinding(active_context_id="ctx"), current_state="stuck")
|
|
636
|
+
o5 = engine.step(s2, transition_id="t1")
|
|
637
|
+
assert "stagnation" in o5.llm_prompt_state
|
|
638
|
+
assert o5.llm_prompt_state["stagnation"]["visits"] == 1
|
|
639
|
+
|
|
640
|
+
# Custom threshold is honored
|
|
641
|
+
s3 = ActiveState(sm, RuntimeBinding(active_context_id="ctx"), current_state="stuck", stagnation_threshold=1)
|
|
642
|
+
s3.register_visit()
|
|
643
|
+
assert s3.is_stagnant is True
|
|
644
|
+
assert s3.visits_remaining == 0
|
|
645
|
+
|
|
646
|
+
# attempt_transition (a real move) does not itself register a visit —
|
|
647
|
+
# only step() (the "what can I do" scan) counts as one
|
|
648
|
+
sm2 = SemanticMap()
|
|
649
|
+
sm2.register_context(ContextPrimitive("ctx2", "Test2"))
|
|
650
|
+
sm2.register_transition(TransitionPrimitive("t2", "Go", "ctx2", "a", "b"))
|
|
651
|
+
engine2 = ThinkingMapTraversal(sm2)
|
|
652
|
+
s4 = engine2.build_active_state(RuntimeBinding(active_context_id="ctx2"), current_state="a")
|
|
653
|
+
engine2.attempt_transition(s4, "t2")
|
|
654
|
+
assert s4.visit_count == 0
|
|
655
|
+
|
|
656
|
+
|
|
599
657
|
def check_idle_outcome():
|
|
600
658
|
"""Verify IDLE outcome for clean terminal states."""
|
|
601
659
|
sm = SemanticMap()
|
|
@@ -1077,6 +1135,7 @@ def main():
|
|
|
1077
1135
|
("end-to-end logic scenario", check_logic_end_to_end),
|
|
1078
1136
|
("horizontal properties (25 items)", check_horizontal_properties),
|
|
1079
1137
|
("TTL evidence decay", check_ttl_decay),
|
|
1138
|
+
("stagnation counter (visit countdown)", check_stagnation_counter),
|
|
1080
1139
|
("IDLE outcome", check_idle_outcome),
|
|
1081
1140
|
("BRIDGE outcome (cross-context)", check_bridge_outcome),
|
|
1082
1141
|
("bridge crossing (validated writeback)", check_bridge_crossing),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fpf-thinking-map
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Agentic thinking map — structured reasoning constraints for LLMs with TTL evidence decay, deterministic guards, and propositional logic glue. Compiled from FPF (First Principles Framework).
|
|
5
5
|
Author-email: "prichindel.com" <igareosh@igareosh.com>
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/igareosh/prichindel.com-agentic-thinking-map
|
|
8
8
|
Project-URL: Repository, https://github.com/igareosh/prichindel.com-agentic-thinking-map
|
|
9
9
|
Project-URL: Documentation, https://github.com/igareosh/prichindel.com-agentic-thinking-map#readme
|
|
@@ -12,7 +12,6 @@ Keywords: agentic,thinking-map,llm,reasoning,propositional-logic,evidence-decay,
|
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
16
15
|
Classifier: Operating System :: OS Independent
|
|
17
16
|
Classifier: Programming Language :: Python :: 3
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -27,24 +26,53 @@ Dynamic: license-file
|
|
|
27
26
|
|
|
28
27
|
# prichindel.com Agentic Thinking Map
|
|
29
28
|
|
|
30
|
-
**v1.
|
|
29
|
+
**v1.4.0** — [FPF (First Principles Framework)](https://github.com/ailev/FPF), compiled into a small traversal map for LLM agents.
|
|
31
30
|
|
|
32
|
-
A Python package that gives
|
|
31
|
+
A Python package that gives a model a bounded move board instead of a giant framework to digest at runtime. Instead of rereading a sprawling semantic corpus and improvising from it, the model gets a small JSON slice: what context it is in, what move is open, what evidence is missing, what is risky, and what outcome class applies.
|
|
33
32
|
|
|
34
33
|
**[Visual architecture →](ARCHITECTURE.md)** — module graph, step flowchart, floor map, evidence lifecycle, slice structure, deploy sequence diagram.
|
|
35
34
|
|
|
35
|
+
## Why this exists
|
|
36
|
+
|
|
37
|
+
FPF is valuable, but it is large, clumsy at runtime, and poorly shaped for direct model consumption. A human can read a 51k-line framework, understand its distinctions, and apply them carefully. A model usually does something else: it absorbs the vocabulary, performs the tone of the framework, and still drifts on the actual task.
|
|
38
|
+
|
|
39
|
+
This package exists because the useful part is not making the model sound more scientific. The useful part is compiling the parts of FPF that help operational decisions into something small, explicit, and inspectable. We took what mattered for bounded traversal, left out what would bloat or bias the model, and evolved the result as publishers of a practical library rather than trying to reproduce the whole upstream framework inside another AI mega-system.
|
|
40
|
+
|
|
41
|
+
The goal is simple: give the model enough structure to behave understandably, without building a cage so elaborate that it becomes another source of drift.
|
|
42
|
+
|
|
43
|
+
We do not compete with FPF and we do not need to. FPF stays FPF: broad, ambitious, and useful as a frame. This library is the smaller usable tool for people who want the frame without carrying the whole corpus into every project.
|
|
44
|
+
|
|
36
45
|
## What it does
|
|
37
46
|
|
|
38
|
-
You define a domain as a semantic map
|
|
47
|
+
You define a domain as a semantic map: contexts, roles, gates, evidence, transitions. The model gets a per-move slice, not a theory dump. Deterministic guards handle the hard checks. Propositional logic rules (NOT, AND, OR, XOR, IMPLIES, IFF) provide explicit decision glue between the semantic primitives and the current state.
|
|
48
|
+
|
|
49
|
+
The model's job is not "what does FPF mean?" It is: **given this map and this state, what is the best lawful next move?**
|
|
50
|
+
|
|
51
|
+
In practice this does two useful things:
|
|
52
|
+
|
|
53
|
+
- it reduces unexplained drift by moving state tracking and hard checks out of freeform model reasoning
|
|
54
|
+
- it gives the model simple, understandable outcomes such as `CONTINUE`, `COLLECT_EVIDENCE`, `BRIDGE`, `IDLE`, `ESCALATE`, instead of making it reconstruct its own epistemic condition from scratch
|
|
55
|
+
|
|
56
|
+
This is not a panacea. Models still miss information. They still drift. But with a bounded traversal map, the failure mode becomes much easier to explain: missing evidence, wrong context, blocked move, stale basis, unlicensed bridge. The weirdness gets smaller because the state is smaller.
|
|
57
|
+
|
|
58
|
+
## Provable practical gains
|
|
39
59
|
|
|
40
|
-
The
|
|
60
|
+
The improvements here are intentionally simple and operational:
|
|
61
|
+
|
|
62
|
+
- less random drift, because the agent reads explicit state instead of reconstructing state from prose
|
|
63
|
+
- fewer unlawful moves, because guards and scoped transitions check them before the model improvises
|
|
64
|
+
- clearer failure, because "why blocked" is surfaced directly
|
|
65
|
+
- smaller runtime payload, because the model gets a slice, not a corpus
|
|
66
|
+
- easier debugging, because outcomes are discrete and inspectable
|
|
67
|
+
|
|
68
|
+
That is the whole point: practical gain, not intellectual theater.
|
|
41
69
|
|
|
42
70
|
## Quick start
|
|
43
71
|
|
|
44
72
|
```bash
|
|
45
73
|
# No dependencies. Python 3.12+.
|
|
46
74
|
|
|
47
|
-
# Verify the package (
|
|
75
|
+
# Verify the package (22 checks)
|
|
48
76
|
python -m fpf_thinking_map.verify
|
|
49
77
|
|
|
50
78
|
# Run the deploy decision scenario
|
|
@@ -60,7 +88,7 @@ fpf_thinking_map/
|
|
|
60
88
|
├── guards.py 9 deterministic guards (context, role, gate, evidence, assignment, speech act, readiness)
|
|
61
89
|
├── logic.py 6 logic operators + decision rules + LogicLayer
|
|
62
90
|
├── traversal.py Step engine with 10 lawful outcomes (incl. IDLE, BRIDGE)
|
|
63
|
-
├── verify.py Self-verification harness (
|
|
91
|
+
├── verify.py Self-verification harness (22/22 checks)
|
|
64
92
|
├── examples.py 5 deploy decision scenarios (missing evidence, role conflict, logic glue, truth table)
|
|
65
93
|
├── README.md Full documentation (any-model readable)
|
|
66
94
|
├── SOURCES.md Source attribution (FPF spec + Mitev lectures)
|
|
@@ -76,6 +104,8 @@ fpf_thinking_map/
|
|
|
76
104
|
|
|
77
105
|
This package is built on [ailev/FPF](https://github.com/ailev/FPF) by Anatoly Levenchuk. It is an independent implementation — our own research and code, MIT-licensed, with further development rights.
|
|
78
106
|
|
|
107
|
+
It is not an attempt to "finish" FPF, replace FPF, or repackage the whole corpus for LLM ingestion. It is a selective compilation for agentic traversal.
|
|
108
|
+
|
|
79
109
|
### What we reviewed
|
|
80
110
|
|
|
81
111
|
We cross-checked the following FPF commits (June 2026 precision restoration cluster) against our code:
|
|
@@ -104,6 +134,33 @@ Two FPF pattern families rejected for activation bias — they amplify existing
|
|
|
104
134
|
|
|
105
135
|
**Design rule**: the map evaluates and constrains moves. It does not propose them. Generative, branch-friendly, candidate-multiplying patterns are the opposite of what a per-move guard-constrained thinking map should contain.
|
|
106
136
|
|
|
137
|
+
## Scope and non-goals
|
|
138
|
+
|
|
139
|
+
This library is intentionally small in scope.
|
|
140
|
+
|
|
141
|
+
- It is for bounded, stepwise agent traversal in a defined domain.
|
|
142
|
+
- It is for making model behavior more understandable, not more magical.
|
|
143
|
+
- It is for simple +/- operational decisions in context, not for open-ended idea generation.
|
|
144
|
+
- It is for constraining and instrumenting an agent run, not replacing the model.
|
|
145
|
+
|
|
146
|
+
It is not:
|
|
147
|
+
|
|
148
|
+
- a full semantic ingestion layer for all of FPF
|
|
149
|
+
- a universal reasoning engine
|
|
150
|
+
- a replacement for ordinary application logic or policy code
|
|
151
|
+
- a proof that an LLM will behave correctly just because the map exists
|
|
152
|
+
- Memory-Augmented Generation (MAG) — no embeddings, no vector store, no cross-session retrieval, ever, inside this engine. Rejected deliberately and permanently, not by omission. See below.
|
|
153
|
+
|
|
154
|
+
## What this actually guarantees
|
|
155
|
+
|
|
156
|
+
fpf does not ship better reasoning. It ships **inspectability**: did the agent follow the lawful path, and was evidence honestly reported at the one place that matters — the wire between what the agent actually did and what this library was told.
|
|
157
|
+
|
|
158
|
+
Take the stagnation counter as the concrete case. It bounds repetition — but only if the integration maps one real attempt to one `step()` call, and only adds evidence when something genuinely new was found. Whether that actually catches a real LLM thrashing depends entirely on whether the calling harness wires evidence honestly, not just "a tool returned something." That wiring discipline lives outside this library, in whatever integrates it — an agent loop, an MCP server, application code. fpf can't verify that discipline was followed; it can only guarantee that if it was, repetition is bounded.
|
|
159
|
+
|
|
160
|
+
That boundary is the correct seam, not a gap to apologize for. Judging whether a piece of evidence is actually meaningful is a semantic question, and semantic questions need prompting, an LLM judge, or domain logic to answer — which is exactly where that belongs: outside fpf, at the evidence-wiring layer, not folded into a library whose entire value is staying small and deterministic. If you want semantics and clever prompting, that's the plug-in point.
|
|
161
|
+
|
|
162
|
+
**This is also why Memory-Augmented Generation (MAG) is rejected as fpf's own architecture, deliberately and permanently.** MAG — retrieval, embeddings, cross-session recall — solves a different problem (what did we discuss three sessions ago) than fpf solves (is this move lawful right now), and it needs exactly the dependency profile this library rules out by design. That is a scope boundary, not a verdict on MAG as a technique: a MAG system is a legitimate thing to run *upstream* of fpf. Whatever it retrieves becomes an evidence_id in `RuntimeBinding.current_evidence` like any other — fpf doesn't care how evidence was produced, only whether it's present, fresh, and licensed. Memory belongs at the evidence-wiring layer, alongside every other semantic judgment this library deliberately doesn't make.
|
|
163
|
+
|
|
107
164
|
## Sources
|
|
108
165
|
|
|
109
166
|
- **[FPF (First Principles Framework)](https://github.com/ailev/FPF)** by Anatoly Levenchuk — transdisciplinary specification (~51k lines). We extracted 10 semantic primitives and 9 guard rules. This is a compiled distillation, not a port.
|
|
@@ -111,6 +168,22 @@ Two FPF pattern families rejected for activation bias — they amplify existing
|
|
|
111
168
|
|
|
112
169
|
Full attribution in [SOURCES.md](fpf_thinking_map/SOURCES.md).
|
|
113
170
|
|
|
171
|
+
## Why it works
|
|
172
|
+
|
|
173
|
+
The core advantage is not "more theory." It is less runtime burden.
|
|
174
|
+
|
|
175
|
+
Without a compiled map, the model keeps re-addressing its own run: am I allowed to move, did I already satisfy the gate, am I missing evidence, am I in the wrong context, am I done or blocked? That self-management loop is where a lot of bad agent behavior comes from.
|
|
176
|
+
|
|
177
|
+
This package turns that loop into a small stateful instrument panel. The model sees what can fire, what cannot, and why. That is enough of an operating surface for many practical agent tasks. Not a panacea, not a grand theory of intelligence, just enough window and file-handles for the model to open the right thing without smashing the house.
|
|
178
|
+
|
|
179
|
+
The bottleneck was never raw model capability — it's self-management overhead eating the capability that's already there. Most orgs running these models, at any scale, hit that ceiling: infra and process that never actually asked the model for full capacity, so upgrading the model changes nothing. This library doesn't make the model smarter. It shrinks what the model has to hold in its head at any one step, so whatever capability is actually there gets spent on the real problem instead of on self-management overhead.
|
|
180
|
+
|
|
181
|
+
Clean product truth:
|
|
182
|
+
|
|
183
|
+
- FPF is the frame.
|
|
184
|
+
- This library is the usable tool.
|
|
185
|
+
- It keeps the frame where it helps, removes the bloat where it hurts, and gives agents a small operational board that produces simpler, more provable behavior.
|
|
186
|
+
|
|
114
187
|
## Why v1.1 exists — reasoning about reasoning is the bug
|
|
115
188
|
|
|
116
189
|
When an LLM navigates a multi-step decision, it faces the same sub-questions at every step: "Is my evidence still valid? Am I going in circles? Is there another path? Why am I blocked?" Without structure, the model re-derives these answers from scratch each time — re-reasoning on its own prior reasoning. Each pass costs tokens, drifts from the original question, and eventually the context fills up with the model arguing with itself about whether it already checked something it checked three steps ago.
|
|
@@ -131,6 +204,18 @@ The model's job shrinks from "figure out the entire epistemic state of your own
|
|
|
131
204
|
- **Evidence status in prompt** — the LLM prompt state now includes per-evidence freshness and TTL remaining. The model sees "test_results: 3 steps left" instead of just "test_results: exists." Decisions informed by countdown, not by guessing.
|
|
132
205
|
- **Response contract** — every slice now ends with a `response_contract`: the structured template the model must fill when responding. Pre-filled fields (scope, basis with freshness/TTL, allowed use, not allowed use, modality, canonical terms, audience) come from the computed state. Empty fields (claim, risky aliases) are for the model. This is why all the code exists — so the contract has precomputed, validated values instead of being re-derived by the model from scratch.
|
|
133
206
|
|
|
207
|
+
## v1.3.0 changes
|
|
208
|
+
|
|
209
|
+
- **Bridge crossing is enforced, not just advertised** — `ActiveState.cross_bridge()` / `ThinkingMapTraversal.attempt_bridge()` actually perform a cross-context hop and check `substitution_license` against `risk_level` before mutating state. An unlicensed bridge under `high`/`critical` risk is refused (`ESCALATE`), not silently allowed. Before this, `bridge_options()` was advisory metadata only — the model decided for itself whether a lossy translation was acceptable.
|
|
210
|
+
- **`include_full_state=False`** — `step()` can now ship the scoped `slice()` alone, without the whole board bolted on. Default stays `True`; opt in when the caller already knows its `transition_id` and wants the lean payload.
|
|
211
|
+
- 21/21 self-verification checks (`python -m fpf_thinking_map.verify`), two new: bridge crossing and lean-slice payload shape.
|
|
212
|
+
|
|
213
|
+
## v1.4.0 changes
|
|
214
|
+
|
|
215
|
+
- **Stagnation counter** — `ActiveState.register_visit()` / `visit_count` / `visits_remaining` / `is_stagnant` count consecutive `step()`s at the same `(context, state)` pair with no new evidence gathered; the counter resets the moment the evidence set changes. `visits_remaining` mirrors `ttl_remaining`'s exact shape — a countdown, not a boolean. Surfaced in both `slice()` and `to_llm_prompt_state()` as a `stagnation` block. Pure signal: no new outcome kind, nothing blocks, no restraint added to the model's options. Closes a real blind spot — `MoveTrace` is deliberately last-move-only (no narrative accumulation), so the engine previously had no way to notice "I've revisited this exact state N times with nothing new to show for it."
|
|
216
|
+
- The guarantee is conditional, and the docs say so plainly: this tracks evidence *set membership*, not evidence *meaning*. It bounds repetition only if the integration maps one real attempt to one `step()` call and only adds evidence that's genuinely new — see [What this actually guarantees](#what-this-actually-guarantees).
|
|
217
|
+
- 22/22 self-verification checks, one new: `check_stagnation_counter`.
|
|
218
|
+
|
|
134
219
|
## Design principles
|
|
135
220
|
|
|
136
221
|
- **Only add structure when it changes agentic behavior** — not for source fidelity alone
|
|
@@ -140,10 +225,10 @@ The model's job shrinks from "figure out the entire epistemic state of your own
|
|
|
140
225
|
|
|
141
226
|
## Using as a dependency
|
|
142
227
|
|
|
143
|
-
This package is the
|
|
228
|
+
This package is the compiled map, not a thinking replacement for the model. Denying unlawful moves is only half the job. The bigger half is returning the lawful surface as a small, plain-JSON slice: what can fire, what is missing, what is risky, why a move is blocked, what response shape is expected. That lets the model self-address its own run with simple signals such as `can_fire`, `blockers`, and `outcome.kind` instead of re-reasoning about its state from prose.
|
|
144
229
|
|
|
145
230
|
```bash
|
|
146
|
-
pip install
|
|
231
|
+
pip install fpf-thinking-map
|
|
147
232
|
```
|
|
148
233
|
|
|
149
234
|
```python
|
|
@@ -207,10 +292,25 @@ Built with Claude Code (Anthropic claude-sonnet-4-6). Tested and verified to wor
|
|
|
207
292
|
|
|
208
293
|
This is not a compliance seal. It means: we used these models against this package and they produced correct, usable results. The per-move slice is small enough for mid-tier models. The logic and guard outputs are plain JSON — no special tokenization or prompt format required.
|
|
209
294
|
|
|
295
|
+
## Why release this
|
|
296
|
+
|
|
297
|
+
We release this because it is useful beyond our own stack.
|
|
298
|
+
|
|
299
|
+
- It captures a practical subset of FPF in a form models can actually use.
|
|
300
|
+
- It gives agent builders a small constraint surface instead of another giant AI framework.
|
|
301
|
+
- It helps turn model failure from mystical drift into inspectable state.
|
|
302
|
+
- It stays intentionally narrow, so it can remain legible instead of becoming another overbuilt "agent platform."
|
|
303
|
+
|
|
304
|
+
## Credits
|
|
305
|
+
|
|
306
|
+
- **igareosh** — project direction, scope discipline, practical use-case pressure, and product truth
|
|
307
|
+
- **Claude Code (Anthropic)** — implementation support, library iteration, and earlier release preparation
|
|
308
|
+
- **Codex / OpenAI** — product framing polish, packaging cleanup, verification, and release-readiness work
|
|
309
|
+
|
|
210
310
|
## License
|
|
211
311
|
|
|
212
312
|
MIT. See [LICENSE](LICENSE).
|
|
213
313
|
|
|
214
314
|
---
|
|
215
315
|
|
|
216
|
-
**prichindel.com** — v1.
|
|
316
|
+
**prichindel.com** — v1.4.0 — 2026-07-07
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fpf-thinking-map"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.4.0"
|
|
4
4
|
description = "Agentic thinking map — structured reasoning constraints for LLMs with TTL evidence decay, deterministic guards, and propositional logic glue. Compiled from FPF (First Principles Framework)."
|
|
5
5
|
readme = "README.md"
|
|
6
|
-
license =
|
|
6
|
+
license = "MIT"
|
|
7
7
|
requires-python = ">=3.12"
|
|
8
8
|
authors = [
|
|
9
9
|
{name = "prichindel.com", email = "igareosh@igareosh.com"},
|
|
@@ -17,7 +17,6 @@ classifiers = [
|
|
|
17
17
|
"Development Status :: 4 - Beta",
|
|
18
18
|
"Intended Audience :: Developers",
|
|
19
19
|
"Intended Audience :: Science/Research",
|
|
20
|
-
"License :: OSI Approved :: MIT License",
|
|
21
20
|
"Operating System :: OS Independent",
|
|
22
21
|
"Programming Language :: Python :: 3",
|
|
23
22
|
"Programming Language :: Python :: 3.12",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map/RELATED_WORK_GOFLOW_FPF_SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fpf_thinking_map-1.3.0 → fpf_thinking_map-1.4.0}/fpf_thinking_map.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|