fix(keys): the per-arm predictions artifact leaves the trader's prefix (alpha-engine-config-I9822) - #207
Merged
Conversation
…x (alpha-engine-config-I9822)
`predictions/` held two artifact shapes: the trader's champion serving feed
(`predictions/{trading_day}.json`, the contract named in `slots/__init__.py`
and AGENTS.md) and the per-arm artifact
(`predictions/{arm~seg}/{trading_day}.json`). A consumer doing
`store.list_keys("predictions/")` saw both and had to discriminate by path
depth. Nothing did, which is what made it a design risk rather than a live
defect.
The per-arm shape moves to `arm_predictions/`, and `predictions_key` is
declared so the trader contract has a single source for its key rather than
living only in prose.
MOVED WHILE THE PREFIX WAS EMPTY. Measured 2026-09-11: zero objects under
`predictions/` in the production store, so this orphaned nothing. The same
change after either shape had been written would have stranded those objects
at an address no code resolves - which is alpha-engine-config-I10498, filed
the same day for a feature layer stranded exactly that way by a content-hash
move. The cheapest moment to separate two artifact shapes is before either
exists, and that moment is now.
Deliverable 1 of the issue was already done: `arm_predictions_key` lives in
`crucible/keys.py` and `slots/inputs.py` imports it from there. Only
deliverable 2 remained.
The new guard is proven red, not assumed: reverting ARM_PREDICTIONS_PREFIX to
"predictions/" fails
test_the_two_shapes_live_under_different_prefixes and
test_a_listing_of_the_feed_prefix_cannot_return_an_arm_artifact.
Two things found on the way:
- `__all__` was out of alphabetical order before this change; the repo's own
TestAllIsSortedAndDeduplicated caught my addition and the pre-existing
disorder together. Re-sorted and de-duplicated, 79 entries.
- The tests went into `tests/test_keys_prefixes.py`, the file that already
owns this class of assertion, rather than the `tests/test_keys.py` the
issue named - which does not exist, and creating it would have made a
second home for one question.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WARhC81oatq9czVeyaM66L
Prepared by: Claude Opus 5 (1M context) via Claude Code Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WARhC81oatq9czVeyaM66L
cipher813
force-pushed
the
fix/arm-predictions-prefix-collision-i9822
branch
from
September 11, 2026 17:52
6587247 to
318dae5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the open half of
alpha-engine-config-I9822.What was wrong
predictions/held two artifact shapes:predictions/{trading_day}.jsoncrucible/slots/__init__.pyand in this repo'sAGENTS.mdpredictions/{arm~seg}/{trading_day}.jsonA consumer doing
store.list_keys("predictions/")saw both and had to discriminate by path depth. Nothing did — which is what kept this a design risk rather than a live defect, and also why it would have been found the hard way.What changed
arm_predictions/, behind a namedARM_PREDICTIONS_PREFIX.predictions_key(trading_day)is declared, so the trader contract has one source for its key instead of living only in prose. The key builder only — writing that artifact is the M slot's job and stays on-I10129. It is declared here becausearm_predictions_keycannot be tested against a collision with a key that does not exist.Moved while the prefix was EMPTY, and that is the point
Measured 2026-09-11: zero objects under
predictions/in the production store.So this rename orphans nothing. The same change made after either shape had been written would have stranded those objects at an address no code resolves — which is
-I10498, filed the same day for a feature layer stranded exactly that way by a content-hash move (532 sessions atvf795db2b5049, unreachable, while live code resolvesv6df3c0a27b70holding 7). The cheapest moment to separate two artifact shapes is before either exists.Deliverable 1 was already done
The issue's first deliverable — move
arm_predictions_keyout ofslots/inputs.pyintokeys.py— is already true onmain: it is atcrucible/keys.py:317andslots/inputs.py:102imports it from there. Only deliverable 2 remained. Noted so the issue's closing comment does not claim work that a previous change did.The guard is proven red, not assumed
Reverting
ARM_PREDICTIONS_PREFIXto"predictions/"and re-running:Four assertions in total, including the adversarial case the shared prefix allowed — an arm whose id looks like a trading day — and one asserting
arm_key_segmentstays invertible and still refuses anarm_idthat already contains~, which is the issue's stated gotcha.Two things found on the way
crucible.keys.__all__was out of alphabetical order before this change. The repo's ownTestAllIsSortedAndDeduplicatedcaught my addition and the pre-existing disorder together. Re-sorted and de-duplicated: 79 entries.tests/test_keys_prefixes.py, the file that already owns this class of assertion, rather than thetests/test_keys.pythe issue named — which does not exist. Creating it would have made a second home for one question. Reality over the issue's guess.Test plan
Full suite green before opening, under the repo's own invocation:
Worth recording: a bare
python3 -m pytestin a worktree reports 8 spurious failures intests/test_deploy.pywithPackageNotFoundError: No package metadata was found for crucible— the laptop's global interpreter, not the repo environment.uv run --frozenis the invocation that measures the repo; the bare one measures the laptop.Prepared by: Claude Opus 5 (1M context) via Claude Code