poseres 2.2.0__tar.gz → 2.3.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.
Files changed (80) hide show
  1. {poseres-2.2.0/src/poseres.egg-info → poseres-2.3.0}/PKG-INFO +1 -1
  2. {poseres-2.2.0 → poseres-2.3.0}/pyproject.toml +1 -1
  3. {poseres-2.2.0 → poseres-2.3.0/src/poseres.egg-info}/PKG-INFO +1 -1
  4. {poseres-2.2.0 → poseres-2.3.0}/src/pra/action/recipe.py +82 -0
  5. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/minecraft/anatomy.py +21 -1
  6. {poseres-2.2.0 → poseres-2.3.0}/LICENSE +0 -0
  7. {poseres-2.2.0 → poseres-2.3.0}/README.md +0 -0
  8. {poseres-2.2.0 → poseres-2.3.0}/setup.cfg +0 -0
  9. {poseres-2.2.0 → poseres-2.3.0}/src/poseres.egg-info/SOURCES.txt +0 -0
  10. {poseres-2.2.0 → poseres-2.3.0}/src/poseres.egg-info/dependency_links.txt +0 -0
  11. {poseres-2.2.0 → poseres-2.3.0}/src/poseres.egg-info/entry_points.txt +0 -0
  12. {poseres-2.2.0 → poseres-2.3.0}/src/poseres.egg-info/requires.txt +0 -0
  13. {poseres-2.2.0 → poseres-2.3.0}/src/poseres.egg-info/top_level.txt +0 -0
  14. {poseres-2.2.0 → poseres-2.3.0}/src/pra/__init__.py +0 -0
  15. {poseres-2.2.0 → poseres-2.3.0}/src/pra/_deprecation.py +0 -0
  16. {poseres-2.2.0 → poseres-2.3.0}/src/pra/action/__init__.py +0 -0
  17. {poseres-2.2.0 → poseres-2.3.0}/src/pra/action/policy.py +0 -0
  18. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/__init__.py +0 -0
  19. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/body.py +0 -0
  20. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/gymnasium_body.py +0 -0
  21. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/minecraft/__init__.py +0 -0
  22. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/minecraft/protocol.py +0 -0
  23. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/minecraft/transport.py +0 -0
  24. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/ros2/__init__.py +0 -0
  25. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/ros2/body.py +0 -0
  26. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/ros2/fake.py +0 -0
  27. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/ros2/specs.py +0 -0
  28. {poseres-2.2.0 → poseres-2.3.0}/src/pra/anatomy/ros2/transport.py +0 -0
  29. {poseres-2.2.0 → poseres-2.3.0}/src/pra/config.py +0 -0
  30. {poseres-2.2.0 → poseres-2.3.0}/src/pra/core/__init__.py +0 -0
  31. {poseres-2.2.0 → poseres-2.3.0}/src/pra/core/bus.py +0 -0
  32. {poseres-2.2.0 → poseres-2.3.0}/src/pra/core/contracts.py +0 -0
  33. {poseres-2.2.0 → poseres-2.3.0}/src/pra/core/engine.py +0 -0
  34. {poseres-2.2.0 → poseres-2.3.0}/src/pra/core/frame.py +0 -0
  35. {poseres-2.2.0 → poseres-2.3.0}/src/pra/core/policies.py +0 -0
  36. {poseres-2.2.0 → poseres-2.3.0}/src/pra/core/scorer.py +0 -0
  37. {poseres-2.2.0 → poseres-2.3.0}/src/pra/dash/__init__.py +0 -0
  38. {poseres-2.2.0 → poseres-2.3.0}/src/pra/dash/cli.py +0 -0
  39. {poseres-2.2.0 → poseres-2.3.0}/src/pra/dash/model.py +0 -0
  40. {poseres-2.2.0 → poseres-2.3.0}/src/pra/dash/page.html +0 -0
  41. {poseres-2.2.0 → poseres-2.3.0}/src/pra/dash/server.py +0 -0
  42. {poseres-2.2.0 → poseres-2.3.0}/src/pra/examples/__init__.py +0 -0
  43. {poseres-2.2.0 → poseres-2.3.0}/src/pra/examples/rover/__init__.py +0 -0
  44. {poseres-2.2.0 → poseres-2.3.0}/src/pra/examples/rover/cli.py +0 -0
  45. {poseres-2.2.0 → poseres-2.3.0}/src/pra/examples/rover/viewer.html +0 -0
  46. {poseres-2.2.0 → poseres-2.3.0}/src/pra/examples/rover/viewer.py +0 -0
  47. {poseres-2.2.0 → poseres-2.3.0}/src/pra/examples/rover/world.py +0 -0
  48. {poseres-2.2.0 → poseres-2.3.0}/src/pra/flush/__init__.py +0 -0
  49. {poseres-2.2.0 → poseres-2.3.0}/src/pra/flush/cli.py +0 -0
  50. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/__init__.py +0 -0
  51. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/acceptance.py +0 -0
  52. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/agency.py +0 -0
  53. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/cli.py +0 -0
  54. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/ladder.py +0 -0
  55. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/report.py +0 -0
  56. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/runner.py +0 -0
  57. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/scale.py +0 -0
  58. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/scan.py +0 -0
  59. {poseres-2.2.0 → poseres-2.3.0}/src/pra/harness/seeding.py +0 -0
  60. {poseres-2.2.0 → poseres-2.3.0}/src/pra/motivation/__init__.py +0 -0
  61. {poseres-2.2.0 → poseres-2.3.0}/src/pra/motivation/context.py +0 -0
  62. {poseres-2.2.0 → poseres-2.3.0}/src/pra/motivation/drive.py +0 -0
  63. {poseres-2.2.0 → poseres-2.3.0}/src/pra/nats/__init__.py +0 -0
  64. {poseres-2.2.0 → poseres-2.3.0}/src/pra/nats/control.py +0 -0
  65. {poseres-2.2.0 → poseres-2.3.0}/src/pra/nats/fake.py +0 -0
  66. {poseres-2.2.0 → poseres-2.3.0}/src/pra/nats/store.py +0 -0
  67. {poseres-2.2.0 → poseres-2.3.0}/src/pra/nats/subjects.py +0 -0
  68. {poseres-2.2.0 → poseres-2.3.0}/src/pra/nats/tap.py +0 -0
  69. {poseres-2.2.0 → poseres-2.3.0}/src/pra/nats/transport.py +0 -0
  70. {poseres-2.2.0 → poseres-2.3.0}/src/pra/persistence/__init__.py +0 -0
  71. {poseres-2.2.0 → poseres-2.3.0}/src/pra/persistence/brain_cli.py +0 -0
  72. {poseres-2.2.0 → poseres-2.3.0}/src/pra/persistence/portable.py +0 -0
  73. {poseres-2.2.0 → poseres-2.3.0}/src/pra/persistence/snapshot.py +0 -0
  74. {poseres-2.2.0 → poseres-2.3.0}/src/pra/persistence/store.py +0 -0
  75. {poseres-2.2.0 → poseres-2.3.0}/src/pra/telemetry/__init__.py +0 -0
  76. {poseres-2.2.0 → poseres-2.3.0}/src/pra/telemetry/recorder.py +0 -0
  77. {poseres-2.2.0 → poseres-2.3.0}/src/pra/world/__init__.py +0 -0
  78. {poseres-2.2.0 → poseres-2.3.0}/src/pra/world/event_source.py +0 -0
  79. {poseres-2.2.0 → poseres-2.3.0}/src/pra/world/ladder.py +0 -0
  80. {poseres-2.2.0 → poseres-2.3.0}/tests/test_hq_structure.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: poseres
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: Pose Resolution Architecture — validation harness and batched in-memory core
5
5
  Author: Daan Gerits
6
6
  License: Copyright (c) 2026 Daan Gerits
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "poseres"
7
- version = "2.2.0"
7
+ version = "2.3.0"
8
8
  description = "Pose Resolution Architecture — validation harness and batched in-memory core"
9
9
  readme = "README.md"
10
10
  # >=3.12 since feature 013: ROS 2 LTS containers bind rclpy to Ubuntu 24.04's
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: poseres
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: Pose Resolution Architecture — validation harness and batched in-memory core
5
5
  Author: Daan Gerits
6
6
  License: Copyright (c) 2026 Daan Gerits
@@ -13,6 +13,19 @@ held at bar, 20/24 provably recipe-led.
13
13
  Recipes are policy-side state, deliberately not snapshot state in v1: they
14
14
  are reconstructible from kept demonstrations (the feature-041 spec records
15
15
  the assumption).
16
+
17
+ Place-keyed futility (feature 045; the-long-carry, episode 0120): without
18
+ a disconfirmation pathway the selection argmax is stateless and the body
19
+ pressed a closed gate for 4,672 of 6,000 life-steps. The measured repair
20
+ (rig prototype K=200/W=800: parking abolished, the revive-peek-wander
21
+ loop emerged, first brain-driven lap crossings) ships here keyed to the
22
+ PLACE — a stalled pointer poisons the quantized subgoal it points at, and
23
+ every recipe currently pointing there is ineligible together until the
24
+ poison expires. Both refuted forms carried numbers: per-recipe erosion
25
+ thrashed at the poison boundary (556 die/revive events in one life) and
26
+ per-recipe hysteresis fell back through the cohort of near-identical
27
+ recipes. Futility state follows the recipe rule above: policy-side, not
28
+ snapshot state.
16
29
  """
17
30
 
18
31
  from __future__ import annotations
@@ -82,6 +95,20 @@ class RecipePolicy(CompletionItchPolicy):
82
95
  added terms are inert and the policy degrades to its parent. Bounded
83
96
  watch counters: ``advance_events`` (subgoal pointer progress) and
84
97
  ``out_of_context`` (no recipe step within 2 blocks — the parrot watch).
98
+
99
+ Place-keyed futility (feature 045; episode 0120 measured, module
100
+ docstring): with ``futility_k > 0``, ``futility_k`` consecutive
101
+ followed steps without pointer advance poison the pointed place —
102
+ the subgoal position rounded to the block grid — for ``futility_w``
103
+ selection steps; recipes whose pointer currently resolves to a
104
+ poisoned place are ineligible, and with none eligible the policy is
105
+ exactly its parent (the wander phase). Expiry is a clean peek: the
106
+ stall count restarts, so re-poisoning takes ``futility_k`` fresh
107
+ steps — the re-check cadence comes from the constants alone. The
108
+ ONLY futility state is per-place (both per-recipe forms are the
109
+ measured failure modes); ``futility_k = 0`` (default) is bit-exact
110
+ pre-045 behavior, RNG stream included. Watch counters:
111
+ ``fatigue_events`` (poisons created), ``revive_events`` (expired).
85
112
  """
86
113
 
87
114
  def __init__(
@@ -102,6 +129,8 @@ class RecipePolicy(CompletionItchPolicy):
102
129
  deficit_kappa: float = 0.0,
103
130
  commit_kappa: float = 0.0,
104
131
  explore_defers_holds: bool = False,
132
+ futility_k: int = 0,
133
+ futility_w: int = 800,
105
134
  ):
106
135
  super().__init__(
107
136
  params,
@@ -121,9 +150,21 @@ class RecipePolicy(CompletionItchPolicy):
121
150
  self.lambda_r = float(lambda_r)
122
151
  self.position_indices = (int(position_indices[0]), int(position_indices[1]))
123
152
  self.position_scale = float(position_scale)
153
+ fk, fw = float(futility_k), float(futility_w)
154
+ if not np.isfinite(fk) or fk < 0.0 or fk != int(fk):
155
+ raise ValueError(f"RecipePolicy: futility_k {futility_k} must be a finite integer >= 0")
156
+ if not np.isfinite(fw) or fw <= 0.0 or fw != int(fw):
157
+ raise ValueError(f"RecipePolicy: futility_w {futility_w} must be a finite integer > 0")
158
+ self.futility_k = int(fk)
159
+ self.futility_w = int(fw)
124
160
  self.advance_events = 0
125
161
  self.out_of_context = 0
162
+ self.fatigue_events = 0
163
+ self.revive_events = 0
126
164
  self._prev_ptr = -1
165
+ self._futility_step = 0
166
+ self._poisons: dict[tuple[int, int], int] = {} # place -> last poisoned step
167
+ self._stall: tuple[tuple[int, int], int] | None = None # (place, count)
127
168
  self._ctx: PolicyContext | None = None
128
169
  self._subgoal: tuple[float, float] | None = None
129
170
  self.potential_of = self._recipe_hold
@@ -132,10 +173,45 @@ class RecipePolicy(CompletionItchPolicy):
132
173
  ix, iz = self.position_indices
133
174
  return float(obs[ix]) * self.position_scale, float(obs[iz]) * self.position_scale
134
175
 
176
+ def _place_key(self, pos: tuple[float, float]) -> tuple[int, int]:
177
+ return int(round(pos[0])), int(round(pos[1]))
178
+
179
+ def _pointed_place(self, ctx: PolicyContext, recipe: Recipe) -> tuple[int, int]:
180
+ """Where this recipe's pointer currently resolves — the
181
+ side-effect-free twin of :meth:`_point_subgoal`'s arithmetic."""
182
+ cur = self._pos(ctx.observation)
183
+ dists = [
184
+ max(abs(self._pos(o)[0] - cur[0]), abs(self._pos(o)[1] - cur[1])) for o in recipe.steps
185
+ ]
186
+ ptr = min(int(np.argmin(dists)) + 1, len(recipe.steps) - 1)
187
+ return self._place_key(self._pos(recipe.steps[ptr]))
188
+
189
+ def _expire_poisons(self) -> None:
190
+ for place in [p for p, last in self._poisons.items() if last < self._futility_step]:
191
+ del self._poisons[place]
192
+ self.revive_events += 1
193
+
194
+ def _track_stall(self, place: tuple[int, int], advanced: bool) -> None:
195
+ if advanced:
196
+ self._stall = None
197
+ return
198
+ count = self._stall[1] + 1 if self._stall is not None and self._stall[0] == place else 1
199
+ if count >= self.futility_k:
200
+ # dead through step + futility_w inclusive: exactly futility_w
201
+ # ineligible selection steps, then the peek
202
+ self._poisons[place] = self._futility_step + self.futility_w
203
+ self._stall = None
204
+ self.fatigue_events += 1
205
+ else:
206
+ self._stall = (place, count)
207
+
135
208
  def _select_recipe(self, ctx: PolicyContext) -> Recipe | None:
136
209
  best, best_v = None, -np.inf
137
210
  weight = 0.0 if self.label_index is None else self._label_weight(ctx.observation)
211
+ poisons = self._poisons if self.futility_k else None
138
212
  for r in self.memory.recipes:
213
+ if poisons and self._pointed_place(ctx, r) in poisons:
214
+ continue
139
215
  v = ctx.drive_value_of(r.terminal)
140
216
  if self.label_index is not None:
141
217
  v += weight * float(r.terminal[self.label_index])
@@ -171,6 +247,12 @@ class RecipePolicy(CompletionItchPolicy):
171
247
 
172
248
  def select_action(self, context: PolicyContext, rng) -> int:
173
249
  self._ctx = context
250
+ if self.futility_k:
251
+ self._futility_step += 1
252
+ self._expire_poisons()
253
+ adv_before = self.advance_events
174
254
  recipe = self._select_recipe(context)
175
255
  self._subgoal = None if recipe is None else self._point_subgoal(context, recipe)
256
+ if self.futility_k and self._subgoal is not None:
257
+ self._track_stall(self._place_key(self._subgoal), self.advance_events > adv_before)
176
258
  return super().select_action(context, rng)
@@ -149,12 +149,26 @@ _AIM = SensorSpec(
149
149
  labels=tuple(f"s{k}" for k in range(8)) + ("drop",),
150
150
  )
151
151
 
152
+ # The peers sense (research topic lean-worlds, licensed by Bar L1,
153
+ # 2026-08-17): the nearest OTHER body, in the drops sense's exact
154
+ # grammar — presence, egocentric bearing, distance, count, and the
155
+ # appearance signature of the world's own username (identity as
156
+ # property; hashed, never parsed). Opt-in; appended LAST so every
157
+ # shipped offset is unchanged.
158
+ _PEERS = SensorSpec(
159
+ id="peers",
160
+ topic="peers",
161
+ width=8,
162
+ labels=("present", "sin_b", "cos_b", "dist", "count", "sig0", "sig1", "sig2"),
163
+ )
164
+
152
165
 
153
166
  def c1_anatomy(
154
167
  crafting: bool = True,
155
168
  survival: bool | None = None,
156
169
  flood: bool | None = None,
157
170
  aim: str | None = None,
171
+ peers: bool = False,
158
172
  ) -> tuple[list[SensorSpec], list[ActuatorSpec]]:
159
173
  """The (sensors, actuators) lists `Ros2Body.factory` expects.
160
174
 
@@ -167,7 +181,9 @@ def c1_anatomy(
167
181
  ``crafting=False``: the exact feature-027 body (14/8).
168
182
  ``flood=True``/``aim="worth"``: the instrument senses individually
169
183
  (module doc); ``aim="salience"`` is bridge behavior only, the
170
- declaration byte-identical to ``aim=""``.
184
+ declaration byte-identical to ``aim=""``. ``peers=True`` appends
185
+ the peers sense LAST (research topic lean-worlds; ships into the
186
+ default only on promotion) — the 94/13 instrument body.
171
187
  """
172
188
  if survival is None:
173
189
  blessed = crafting # the zero-override default: design 0015's stack
@@ -189,6 +205,8 @@ def c1_anatomy(
189
205
  raise ValueError(f"unknown aim form {aim!r}: expected '', 'salience', or 'worth'")
190
206
  if aim and not survival:
191
207
  raise ValueError("the aim is a survival-instrument sense: it needs the distal body")
208
+ if peers and not survival:
209
+ raise ValueError("the peers sense is a survival-instrument sense: it needs the distal body")
192
210
  sensors = list(_BASE_SENSORS) + (list(_PROPERTY_SENSORS) if crafting else [])
193
211
  if survival:
194
212
  sensors = [_SURVIVAL_HAND if s.id == "hand" else s for s in sensors]
@@ -197,6 +215,8 @@ def c1_anatomy(
197
215
  sensors.append(_FLOOD)
198
216
  if aim == "worth":
199
217
  sensors.append(_AIM)
218
+ if peers:
219
+ sensors.append(_PEERS)
200
220
  presets = _BASE_PRESETS + (_GRID_PRESETS if crafting else ())
201
221
  presets += _SURVIVAL_PRESETS if survival else ()
202
222
  return sensors, [ActuatorSpec(id="control", topic="control", presets=presets)]
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
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
File without changes
File without changes
File without changes
File without changes
File without changes