fpf-thinking-map 1.4.1__tar.gz → 1.4.2__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.
Files changed (29) hide show
  1. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/PKG-INFO +8 -3
  2. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/README.md +7 -2
  3. fpf_thinking_map-1.4.2/fpf_thinking_map/ADVISORIES.md +71 -0
  4. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map.egg-info/PKG-INFO +8 -3
  5. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/pyproject.toml +1 -1
  6. fpf_thinking_map-1.4.1/fpf_thinking_map/ADVISORIES.md +0 -29
  7. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/LICENSE +0 -0
  8. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/FPF_AUDIT_RESPONSE.md +0 -0
  9. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/FPF_FLOOR_MAP.md +0 -0
  10. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/FPF_SOURCE_TO_CODE_RELATION_AUDIT.md +0 -0
  11. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/README.md +0 -0
  12. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/REJECTED_C32_CANDIDATE_SYNTHESIS.md +0 -0
  13. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/REJECTED_NQD_OEE_CULTURAL_EVOLUTION.md +0 -0
  14. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/RELATED_WORK_GOFLOW_FPF_SKILL.md +0 -0
  15. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/SOURCES.md +0 -0
  16. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/WHY_THIS_EXISTS.md +0 -0
  17. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/__init__.py +0 -0
  18. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/examples.py +0 -0
  19. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/guards.py +0 -0
  20. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/logic.py +0 -0
  21. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/primitives.py +0 -0
  22. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/py.typed +0 -0
  23. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/state.py +0 -0
  24. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/traversal.py +0 -0
  25. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map/verify.py +0 -0
  26. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map.egg-info/SOURCES.txt +0 -0
  27. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map.egg-info/dependency_links.txt +0 -0
  28. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/fpf_thinking_map.egg-info/top_level.txt +0 -0
  29. {fpf_thinking_map-1.4.1 → fpf_thinking_map-1.4.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fpf-thinking-map
3
- Version: 1.4.1
3
+ Version: 1.4.2
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
6
  License-Expression: MIT
@@ -26,7 +26,7 @@ Dynamic: license-file
26
26
 
27
27
  # prichindel.com Agentic Thinking Map
28
28
 
29
- **v1.4.1** — [FPF (First Principles Framework)](https://github.com/ailev/FPF), compiled into a small traversal map for LLM agents.
29
+ **v1.4.2** — [FPF (First Principles Framework)](https://github.com/ailev/FPF), compiled into a small traversal map for LLM agents.
30
30
 
31
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.
32
32
 
@@ -229,6 +229,11 @@ The model's job shrinks from "figure out the entire epistemic state of your own
229
229
  - `dev_mcp` gains `get_advisories()`, same read-the-doc pattern as `get_fpf_source_mapping`/`get_audit_gaps`.
230
230
  - 13/13 `dev_mcp` self-test checks (one new).
231
231
 
232
+ ## v1.4.2 changes
233
+
234
+ - **Four more advisories** (`ADV-03`–`ADV-06`), found the same way as `ADV-01`/`ADV-02` — running scenarios through `dev_mcp`, not inspection. The one to actually read: **`ADV-03`** — `RuntimeBinding.active_context_id` is self-asserted input, never verified against having actually crossed a bridge; a caller can claim any context directly and get the identical `CONTINUE` a licensed `cross_bridge()` call would produce. `ADV-04` — contradiction detection between `DecisionRule`s is opt-in via `exclusive_with`, not inferred from opposite-looking action names. `ADV-05` — gate `DEGRADE` only distinguishes partial evidence when related facts are grouped into *one* `GateCheck`; split across separate checks, "one of three known" collapses to indistinguishable from "none known." `ADV-06` — `agency_level` (PASSIVE/REACTIVE/AUTONOMOUS/DELIBERATIVE) is descriptive metadata only, same shape as `risk_level` (`ADV-02`) — nothing stops a `PASSIVE` role from firing what a `DELIBERATIVE` role can.
235
+ - `check_advisories_content` now asserts all six advisory IDs are present, not just the original two.
236
+
232
237
  ## Design principles
233
238
 
234
239
  - **Only add structure when it changes agentic behavior** — not for source fidelity alone
@@ -326,4 +331,4 @@ MIT. See [LICENSE](LICENSE).
326
331
 
327
332
  ---
328
333
 
329
- **prichindel.com** — v1.4.1 — 2026-07-08
334
+ **prichindel.com** — v1.4.2 — 2026-07-08
@@ -1,6 +1,6 @@
1
1
  # prichindel.com Agentic Thinking Map
2
2
 
3
- **v1.4.1** — [FPF (First Principles Framework)](https://github.com/ailev/FPF), compiled into a small traversal map for LLM agents.
3
+ **v1.4.2** — [FPF (First Principles Framework)](https://github.com/ailev/FPF), compiled into a small traversal map for LLM agents.
4
4
 
5
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
 
@@ -203,6 +203,11 @@ The model's job shrinks from "figure out the entire epistemic state of your own
203
203
  - `dev_mcp` gains `get_advisories()`, same read-the-doc pattern as `get_fpf_source_mapping`/`get_audit_gaps`.
204
204
  - 13/13 `dev_mcp` self-test checks (one new).
205
205
 
206
+ ## v1.4.2 changes
207
+
208
+ - **Four more advisories** (`ADV-03`–`ADV-06`), found the same way as `ADV-01`/`ADV-02` — running scenarios through `dev_mcp`, not inspection. The one to actually read: **`ADV-03`** — `RuntimeBinding.active_context_id` is self-asserted input, never verified against having actually crossed a bridge; a caller can claim any context directly and get the identical `CONTINUE` a licensed `cross_bridge()` call would produce. `ADV-04` — contradiction detection between `DecisionRule`s is opt-in via `exclusive_with`, not inferred from opposite-looking action names. `ADV-05` — gate `DEGRADE` only distinguishes partial evidence when related facts are grouped into *one* `GateCheck`; split across separate checks, "one of three known" collapses to indistinguishable from "none known." `ADV-06` — `agency_level` (PASSIVE/REACTIVE/AUTONOMOUS/DELIBERATIVE) is descriptive metadata only, same shape as `risk_level` (`ADV-02`) — nothing stops a `PASSIVE` role from firing what a `DELIBERATIVE` role can.
209
+ - `check_advisories_content` now asserts all six advisory IDs are present, not just the original two.
210
+
206
211
  ## Design principles
207
212
 
208
213
  - **Only add structure when it changes agentic behavior** — not for source fidelity alone
@@ -300,4 +305,4 @@ MIT. See [LICENSE](LICENSE).
300
305
 
301
306
  ---
302
307
 
303
- **prichindel.com** — v1.4.1 — 2026-07-08
308
+ **prichindel.com** — v1.4.2 — 2026-07-08
@@ -0,0 +1,71 @@
1
+ # Advisories for integrators
2
+
3
+ Not defects. These are places where `fpf_thinking_map` deliberately stays minimal and leaves a real decision to whoever builds a domain map on top of it — `scope="user-extension"` territory, not something the publisher will fold into the core, because building it in would mean guessing your domain's actual requirement instead of you stating it explicitly.
4
+
5
+ Each advisory: what the default behavior actually is, why that's the default, and exactly how to get stricter behavior if your domain needs it.
6
+
7
+ ---
8
+
9
+ ## ADV-01 — Evidence staleness warns, it does not block
10
+
11
+ **What**: evidence past its TTL (`Freshness.EXPIRED`) still satisfies a transition's `required_evidence`. The engine computes and reports the expiry accurately — `effective_freshness()`, `ttl_remaining()` — and the guard layer raises a `WARN` (`"Evidence '...' is expired"`), but a `WARN` never blocks a move. Only `DENY` (guard) or `BLOCK`/`ABSTAIN` (gate) do.
12
+
13
+ **Why this is the default**: the library doesn't know whether staleness should be advisory or fatal for your domain. A support-ticket confirmation going stale after 48 hours might be fine to act on with a visible warning attached — a human can see it happened. A safety-critical sign-off going stale might need to hard-stop the transition entirely. Building either assumption into the core means guessing wrong for someone else's domain.
14
+
15
+ **How to get a hard block**: attach the evidence to the transition via a `GatePrimitive`/`GateCheck` instead of relying on bare `required_evidence` alone. Gate evaluation is where `ABSTAIN`/`BLOCK` live — write a guard or `LogicLayer` rule using `EvidenceFresh(...)` that checks freshness explicitly and drives the gate to `BLOCK` when the evidence is `EXPIRED`, not merely present.
16
+
17
+ ---
18
+
19
+ ## ADV-02 — `risk_level` doesn't filter transitions on its own
20
+
21
+ **What**: `possible_transitions` is scoped by `(context, current_state)` only. Setting `binding.risk_level = "critical"` doesn't remove or add any transitions — a `critical` and a `normal` binding see the identical transition list from the same state.
22
+
23
+ **Why this is the default**: risk-based branching is a domain policy, not a structural fact about the map. The library has no way to know which of your transitions should be risk-gated and which are risk-agnostic — that's a judgment call about your process, not fpf's to make.
24
+
25
+ **How to get risk-based routing**: use `LogicLayer` with a `RiskAbove(threshold)` proposition driving a `DecisionRule`, or a guard scoped to the specific transition, so the decision to allow, deny, or route by `risk_level` is computed by the engine — not left for the calling model to infer from a raw number it was handed and no instructions on what to do with it.
26
+
27
+ ---
28
+
29
+ ## ADV-03 — `active_context_id` is self-asserted, not verified against how you got there
30
+
31
+ **The sharpest one here — read this before trusting a bridge for anything security-adjacent.**
32
+
33
+ **What**: `RuntimeBinding.active_context_id` is plain input, fresh on every call. Nothing checks that a caller claiming to be in `"exec_queue"` actually arrived there via `attempt_bridge()`/`cross_bridge()`. Constructing a new binding with `active_context_id="exec_queue"` directly succeeds identically to crossing the licensed bridge — same `CONTINUE` outcome, no distinction, no record that the formal path was skipped.
34
+
35
+ **Why this is the default**: the engine is stateless per call — it has no session, no identity, no memory of a prior binding unless you hand it one (`ActiveState` objects can be reused across `step()` calls, but a *fresh* `build_active_state()` call has no way to know what came before it). `#26`'s bridge licensing (`substitution_license`, `translation_loss` vs. `risk_level`) governs the *transition function* `cross_bridge()` exposes — it was never a claim that the engine authenticates *how* a binding's `active_context_id` came to be what it is. That's a harness-level responsibility, not something a per-call traversal engine can enforce on its own.
36
+
37
+ **How to close the gap**: if which context an agent is "in" needs to be trustworthy, the calling harness must be the one enforcing continuity — persist the `ActiveState` object itself (or its `active_context_id`) across the session rather than reconstructing bindings from scratch on each call, and never accept an externally supplied `active_context_id` without validating it came from your own prior `cross_bridge()` call. This is the same shape as ADV-01/ADV-02: fpf computes the right answer when asked through the right door, but doesn't — can't — stop you from walking in the window.
38
+
39
+ ---
40
+
41
+ ## ADV-04 — Contradiction detection is opt-in, not inferred from action names
42
+
43
+ **What**: `LogicLayer.consistency_check()` only flags a contradiction between two `DecisionRule`s that explicitly declare each other via `exclusive_with`. Two satisfied rules recommending literally opposite actions (`"proceed"` vs. `"hold"`) produce no contradiction and no warning unless each rule's `exclusive_with` names the other's action.
44
+
45
+ **Why this is the default**: the engine has no semantic understanding of action strings — `"proceed"` and `"hold"` are opaque labels to it, not known opposites. Inferring opposition from string content would mean guessing at your domain's vocabulary; `exclusive_with` makes the domain author state the relationship explicitly instead.
46
+
47
+ **How to get it caught**: when two rules can fire on the same evidence and their actions are meant to be mutually exclusive, declare it both ways — `exclusive_with=["hold"]` on the rule that can produce `"proceed"`, `exclusive_with=["proceed"]` on the one that can produce `"hold"`. Confirmed working once declared: `step()` returns `ABSTAIN` with `"Logic contradiction: [...]"` in the reason.
48
+
49
+ ---
50
+
51
+ ## ADV-05 — Gate `DEGRADE` only distinguishes partial evidence within a single `GateCheck`
52
+
53
+ **What**: `GatePrimitive.evaluate()` returns `DEGRADE` only when at least one of its `GateCheck`s individually evaluates to `DEGRADE` — which only happens when *that check's own* `required_evidence` list has some, but not all, items present. A gate built from several single-evidence `GateCheck`s (one check per fact) can never produce `DEGRADE`: each check is binary (fully satisfied → `PASS`, or fully missing → `ABSTAIN`), so "one of three facts known" looks identical to "zero of three facts known" at the gate level — both `ABSTAIN`.
54
+
55
+ **Why this is the default**: `DEGRADE` is a property of a single check's internal completeness, not an aggregate computed across independent checks — aggregating "3 truths, 4 known, 1 missing" would require a policy choice (a threshold? a weighting?) the library isn't in a position to guess.
56
+
57
+ **How to get partial visible as `DEGRADE`**: group evidence that should be assessed together into *one* `GateCheck`'s `required_evidence` list (e.g. `GateCheck("tests", "...", required_evidence=["unit_tests_passed", "integration_tests_passed"])`) rather than splitting related facts across separate checks. Confirmed: none → `insufficient`, partial (one of two, grouped) → `partial`, full → `pass` — exactly distinguishable, but only with this grouping.
58
+
59
+ ---
60
+
61
+ ## ADV-06 — `agency_level` is descriptive metadata, not an enforced permission
62
+
63
+ **What**: `RolePrimitive.agency_level` (`PASSIVE` / `REACTIVE` / `AUTONOMOUS` / `DELIBERATIVE`) is surfaced to the model (`to_llm_prompt_state()`'s `active_roles[].agency`) but doesn't gate anything by default. A role bound as `PASSIVE` can fire the exact same transition as one bound `DELIBERATIVE` — identical `CONTINUE`, no distinction.
64
+
65
+ **Why this is the default**: same shape as `risk_level` (ADV-02) — whether "passive" should mean "cannot trigger this class of transition" is a domain policy question the primitive alone can't answer, because not every transition in every domain needs agency-gating.
66
+
67
+ **How to enforce it**: write a guard (or `LogicLayer` rule) scoped to the transitions that should be agency-gated, checking `state.active_roles` for the required `agency_level` before allowing the move — the same pattern as wiring risk-based routing in ADV-02.
68
+
69
+ ---
70
+
71
+ *v1 — 2026-07-08 (ADV-01/02), v2 — 2026-07-08 (ADV-03..06). All found by actually running scenarios through `dev_mcp` (`scope="core"`), not by inspection or guesswork. More advisories get added here the same way — dug up, not invented.*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fpf-thinking-map
3
- Version: 1.4.1
3
+ Version: 1.4.2
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
6
  License-Expression: MIT
@@ -26,7 +26,7 @@ Dynamic: license-file
26
26
 
27
27
  # prichindel.com Agentic Thinking Map
28
28
 
29
- **v1.4.1** — [FPF (First Principles Framework)](https://github.com/ailev/FPF), compiled into a small traversal map for LLM agents.
29
+ **v1.4.2** — [FPF (First Principles Framework)](https://github.com/ailev/FPF), compiled into a small traversal map for LLM agents.
30
30
 
31
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.
32
32
 
@@ -229,6 +229,11 @@ The model's job shrinks from "figure out the entire epistemic state of your own
229
229
  - `dev_mcp` gains `get_advisories()`, same read-the-doc pattern as `get_fpf_source_mapping`/`get_audit_gaps`.
230
230
  - 13/13 `dev_mcp` self-test checks (one new).
231
231
 
232
+ ## v1.4.2 changes
233
+
234
+ - **Four more advisories** (`ADV-03`–`ADV-06`), found the same way as `ADV-01`/`ADV-02` — running scenarios through `dev_mcp`, not inspection. The one to actually read: **`ADV-03`** — `RuntimeBinding.active_context_id` is self-asserted input, never verified against having actually crossed a bridge; a caller can claim any context directly and get the identical `CONTINUE` a licensed `cross_bridge()` call would produce. `ADV-04` — contradiction detection between `DecisionRule`s is opt-in via `exclusive_with`, not inferred from opposite-looking action names. `ADV-05` — gate `DEGRADE` only distinguishes partial evidence when related facts are grouped into *one* `GateCheck`; split across separate checks, "one of three known" collapses to indistinguishable from "none known." `ADV-06` — `agency_level` (PASSIVE/REACTIVE/AUTONOMOUS/DELIBERATIVE) is descriptive metadata only, same shape as `risk_level` (`ADV-02`) — nothing stops a `PASSIVE` role from firing what a `DELIBERATIVE` role can.
235
+ - `check_advisories_content` now asserts all six advisory IDs are present, not just the original two.
236
+
232
237
  ## Design principles
233
238
 
234
239
  - **Only add structure when it changes agentic behavior** — not for source fidelity alone
@@ -326,4 +331,4 @@ MIT. See [LICENSE](LICENSE).
326
331
 
327
332
  ---
328
333
 
329
- **prichindel.com** — v1.4.1 — 2026-07-08
334
+ **prichindel.com** — v1.4.2 — 2026-07-08
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fpf-thinking-map"
3
- version = "1.4.1"
3
+ version = "1.4.2"
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
6
  license = "MIT"
@@ -1,29 +0,0 @@
1
- # Advisories for integrators
2
-
3
- Not defects. These are places where `fpf_thinking_map` deliberately stays minimal and leaves a real decision to whoever builds a domain map on top of it — `scope="user-extension"` territory, not something the publisher will fold into the core, because building it in would mean guessing your domain's actual requirement instead of you stating it explicitly.
4
-
5
- Each advisory: what the default behavior actually is, why that's the default, and exactly how to get stricter behavior if your domain needs it.
6
-
7
- ---
8
-
9
- ## ADV-01 — Evidence staleness warns, it does not block
10
-
11
- **What**: evidence past its TTL (`Freshness.EXPIRED`) still satisfies a transition's `required_evidence`. The engine computes and reports the expiry accurately — `effective_freshness()`, `ttl_remaining()` — and the guard layer raises a `WARN` (`"Evidence '...' is expired"`), but a `WARN` never blocks a move. Only `DENY` (guard) or `BLOCK`/`ABSTAIN` (gate) do.
12
-
13
- **Why this is the default**: the library doesn't know whether staleness should be advisory or fatal for your domain. A support-ticket confirmation going stale after 48 hours might be fine to act on with a visible warning attached — a human can see it happened. A safety-critical sign-off going stale might need to hard-stop the transition entirely. Building either assumption into the core means guessing wrong for someone else's domain.
14
-
15
- **How to get a hard block**: attach the evidence to the transition via a `GatePrimitive`/`GateCheck` instead of relying on bare `required_evidence` alone. Gate evaluation is where `ABSTAIN`/`BLOCK` live — write a guard or `LogicLayer` rule using `EvidenceFresh(...)` that checks freshness explicitly and drives the gate to `BLOCK` when the evidence is `EXPIRED`, not merely present.
16
-
17
- ---
18
-
19
- ## ADV-02 — `risk_level` doesn't filter transitions on its own
20
-
21
- **What**: `possible_transitions` is scoped by `(context, current_state)` only. Setting `binding.risk_level = "critical"` doesn't remove or add any transitions — a `critical` and a `normal` binding see the identical transition list from the same state.
22
-
23
- **Why this is the default**: risk-based branching is a domain policy, not a structural fact about the map. The library has no way to know which of your transitions should be risk-gated and which are risk-agnostic — that's a judgment call about your process, not fpf's to make.
24
-
25
- **How to get risk-based routing**: use `LogicLayer` with a `RiskAbove(threshold)` proposition driving a `DecisionRule`, or a guard scoped to the specific transition, so the decision to allow, deny, or route by `risk_level` is computed by the engine — not left for the calling model to infer from a raw number it was handed and no instructions on what to do with it.
26
-
27
- ---
28
-
29
- *v1 — 2026-07-08. Both found by actually running scenarios through `dev_mcp` (`scope="core"`), not by inspection or guesswork. More advisories get added here the same way — dug up, not invented.*