Metadata-Version: 2.4
Name: keble-positioning
Version: 0.10.12
Summary: Positioning (axes/tags/records) for Keble v2.1 market exploration.
Author-email: zhenhao-ma <bob0103779@gmail.com>
Requires-Python: <3.14,>=3.13
Requires-Dist: griffe<2,>=1.14
Requires-Dist: keble-db<2.0.0,>=1.6.2
Requires-Dist: keble-helpers<2.0.0,>=1.12.6
Requires-Dist: keble-segmenting<1,>=0.11.12
Requires-Dist: keble-task<3.0.0,>=2.4.11
Requires-Dist: pydantic-ai-slim<2.0.0,>=1.41.0
Requires-Dist: pydantic<3.0.0,>=2
Description-Content-Type: text/markdown

# keble-positioning

`keble-positioning` is a thin bridge between datasource-backed positioning records and the canonical `keble-segmenting` runtime.

## Package Line

1. Package version: `0.10.12`
2. Python baseline: `>=3.13,<3.14`
3. Environment manager: `uv` only
4. Segmenting dependency line: `keble-segmenting >=0.11.12,<1`
5. Task dependency line: `keble-task >=2.4.11,<3.0.0`

## Version 0.10.12 Segmenting Coverage Signature Bridge

- Local uv development now consumes `keble-segmenting 0.11.12`, where coverage
  source signatures include mask semantics and completion events are
  envelope-idempotent.
- Positioning now passes the current grid masks into segmenting coverage
  signature/view-state calls so visible coverage invalidates when mask
  definitions or preset semantics change.
- Publish metadata no longer carries the invalid private classifier string that
  PyPI rejects for public package uploads.

## Version 0.10.11 Review Cleanup

- Local uv development keeps exactly one bundled segmenting wheel: the
  `keble-segmenting` source declared in `pyproject.toml`.
- Package contract tests now reject stale historical `keble_segmenting-*.whl`
  artifacts so future dependency bumps cannot leave multiple segmenting payloads
  in the same repo line.
- Auto-mask metadata remains a bridge contract: positioning validates and
  carries `PositioningTaskMetadata.mask_generation_enabled` / `auto_mask_types`,
  while backend owns the post-bootstrap `aauto_segment_and_mask(...)` call.

## Version 0.10.10 Progressive Bootstrap View Events

- Positioning bootstrap emits the existing `UPSERT_POSITIONING_VIEW` event once
  the positioning shell exists, then emits it again after initial dimensions are
  discovered.
- `PositioningViewBase.display_dimension_ids=[]` is now the valid shell-view
  state before any display dimensions exist. User view updates still require a
  meaningful non-empty display-dimension patch.
- Shell view reads skip segmenting coverage aggregation until display
  dimensions exist, so task-room subscribers can render the room immediately
  without queueing coverage or leaking zero-axis coverage errors.

## Version 0.10.9 Segmenting Mutation Tool Contract

- Positioning mutation tool registration now gives `mutate_segmenting` an
  explicit rebucketing contract by default.
- Price-band split, merge, and rebucketing requests must not relabel old option
  keys with `UPDATE_DIMENSION_OPTIONS`.
- The required flow is to delete retired option keys, create fresh option
  buckets, and finish with `AUTO_SEGMENT_AND_MASK` for the affected dimension so
  products move into the correct cells.

## Version 0.10.8 Bootstrap Prompt Context Propagation

- `PositioningTaskMetadata.to_segmenting_prompt_context()` is now the single
  task-owned conversion path from positioning metadata to segmenting prompt
  context.
- Bootstrap dimension discovery forwards that typed context into
  `SegmentingClient.adiscover_dimensions(...)`, so the user's original prompt,
  language, and marketplace policy reach the initial root-axis discovery step.
- Older queued tasks without `prompt_context` rebuild the same typed context
  from `positioning_context`, `language`, and `marketplace`; no keyword-based
  off-scope guard is introduced in this release.

## Version 0.10.7 Merged Context Metadata

- This release supersedes `0.10.6` after the context branch merged with the
  already-published `0.10.5` item title fragment line.
- `PositionableItem.title_fragments` and `PositioningTaskMetadata.prompt_context`
  are both present in the same package line so backend consumers do not lose the
  item display contract while adopting prompt-context inheritance.

## Version 0.10.6 Prompt Context Metadata

- `PositioningTaskMetadata` carries optional `prompt_context` typed as
  `SegmentingPromptContext` so backend root tasks and reduced child tasks can
  preserve the user prompt, output language, and marketplace policy across
  queued segmenting work.
- The field is optional for older queued tasks; callers should prefer it when
  present and fall back to loose `positioning_context`, `language`, and
  `marketplace` fields only for legacy rows.
- This release builds on `0.10.5` item title fragments rather than replacing
  that display metadata contract.

## Version 0.10.5 Item Title Fragments

- `PositionableItem` now carries provider-owned `title_fragments`, defaulting
  to an empty list for existing payload compatibility.
- The field is serialized into `PositionableItemRecord.item_payload` so hosts
  can build compact relationship-group titles without parsing commerce-specific
  nested payloads.
- Positioning still treats the fragments as display data only; provider item
  classes own the meaning and ordering of those fragments.
- `PositioningTaskMetadata.prompt_context` remains typed through
  `SegmentingPromptContext` so backend child queues can inherit prompt,
  language, and marketplace context without string parsing.

## Version 0.10.4 Lock Refresh

- Local uv development still consumes `keble-segmenting 0.11.4`.
- The package lock now records the current bundled wheel hash so `uv run` and
  `uv sync` can install the bridge without a stale same-version artifact
  mismatch.
- No segmenting contract changed in this patch; the refresh only repairs the
  positioning consumer artifact state before backend consumes `0.10.4`.

## Version 0.10.3 Auto-Mask Default Bridge

- `PositioningTaskMetadata.auto_mask_types` can carry a per-task preset mask
  allowlist for the backend-managed post-bootstrap segmenting run.
- `PositioningClient(default_auto_mask_types=...)` is bridge plumbing only:
  positioning applies the host default to omitted `AUTO_SEGMENT_AND_MASK`
  actions, while explicit `auto_mask_types=[]` still disables preset stages.
- This package does not own the default allowlist. Backend hosts decide whether
  feasibility is part of their default positioning flow.

## Version 0.10.2 Pair Default View Source

- `PositioningView` now stores `display_source` as `AUTO` or `USER`.
- AUTO views can follow the product default as preset dimensions arrive:
  pricing first, features/functionality second, scene/use-case as fallback, then
  grid order.
- USER views preserve explicit manual display choices, including
  pricing + scene, and `aupdate_view(...)` marks display-dimension updates as
  USER unless the caller already supplied a source.
- Positioning coverage reads continue to delegate durable readiness to
  `keble-segmenting 0.11.3` pair-based coverage scopes.

## Version 0.10.1 Update

- `PositioningViewDetailed` now includes package-owned
  `coverage_state`, derived from exact segmenting coverage for the displayed
  dimension ids and current grouped item source.
- Missing exact coverage derives `NOT_LOADED` instead of relying on aggregate
  cells to infer whether a selected dimension combination has ever been
  queued.
- Added typed coverage claim helpers for backend owner view updates. Owners can
  queue/retry unloaded or failed coverage, while non-owner reads stay
  read-only.
- The package now consumes `keble-segmenting 0.11.2` so coverage signatures,
  Mongo rows, and phase state enums come from the segmenting source of truth.

## Version 0.10.0 Update

- The package now consumes `keble-segmenting 0.10.4`, including typed OTHER
  dimension options, segmenting-owned Infos, `cell` mask-result payloads, and
  demand/sales metric summaries.
- Reduced-child bootstrap now shares the source grid's Infos row when selected
  item scopes point to one unambiguous source context. Multi-source children
  still create a fresh Infos row because their reusable market context is not
  singular.
- Positioning view/detail payloads keep delegating cells, option roles, preset
  mask types, and metric summaries to segmenting-owned schemas instead of
  duplicating those contracts.
- Test dependencies include `socksio` so HTTPX can run under developer SOCKS
  proxy environments during live/model-backed package tests.

## Version 0.9.5 Update

- `PositioningTaskMetadata` now uses the general `mask_generation_enabled`
  field that matches `keble-segmenting 0.8.5`.
- Lightweight host-owned preview tasks can set the flag to `False` to generate
  dimensions and cell membership without any generated mask work.
- The old preset-only mask field was removed rather than kept as an alias.

## Version 0.9.4 Update

- `PositioningTaskMetadata` now accepts optional `preset_dimension_types` and
  forwards them to segmenting bootstrap discovery.
- `FreshItemsRequest` forwards persisted `positioning_metadata` to host
  callbacks so backend-owned preview filters can stay typed instead of being
  embedded in prompt text.
- Lightweight AMZ setup previews can request pricing and feature axes while
  keeping full positioning tasks on normal open-ended discovery.

## Version 0.9.3 Update

- `PositioningTaskMetadata` added a preview-facing mask override through the
  existing backend bridge.
- Lightweight host-owned preview tasks can set the flag to `False` to generate
  dimensions and cell membership without generated masks.

## Version 0.9.2 Update

- `PositioningTaskMetadata` now accepts optional `owner_type` so backend task
  envelopes can carry seller-profile scope into segmenting progress and preset
  market reasoning without breaking already queued legacy tasks.

## Version 0.9.1 Update

- The package now consumes `keble-segmenting 0.6.1`, where stale direct-result
  test/API residue from the multi-select rewrite is removed.
- Local uv development resolves the same `keble_segmenting-0.6.1` wheel as the
  current backend line, so package-contract tests exercise the active cleanup
  release.
- Runtime positioning behavior is unchanged from `0.9.0`; this is a dependency
  consumption and repo-hygiene release.

## Version 0.9.0 Update

- The package now consumes `keble-segmenting 0.6.0`, where segmented results
  store `option_keys` and multi-select dimensions expand one item into multiple
  cell placements.
- View-detail reads continue to delegate placement counts to segmenting
  aggregation; positioning does not reimplement cartesian cell expansion.

## Version 0.8.1 Update

- View-detail display-axis resolution now preserves every valid saved view
  exactly, including user-selected pricing + scene/use-case pairs.
- Preset-priority defaults are still used when no saved view exists, preferring
  pricing, then features/functionality, then scene/use-case, then grid order.
- The stale first-N replacement heuristic was removed so valid user choices are
  never mistaken for old auto defaults.

## Version 0.8.0 Update

- Local uv development now resolves `keble-segmenting 0.5.0`, which adds
  durable terminal omitted segmentation rows and aggregate empty-vs-processing
  status semantics for lazy positioning axes.
- Runtime view-detail aggregation still relies on the package-owned
  segmenting aggregate contract; no positioning workaround or copied omitted
  result payload is introduced.

## Version 0.7.6 Update

- Local uv development now resolves `keble-segmenting 0.4.9`, matching the
  backend current-line lazy auto-segment bootstrap fix.
- The package dependency floor is raised to `keble-segmenting >=0.4.9,<1` so
  positioning package-contract tests cannot drift behind the segmenting line
  consumed by backend workers.
- Runtime positioning behavior is unchanged from `0.7.5`; this patch keeps
  dependency metadata, local wheel sources, lockfile, and docs aligned.

## Version 0.7.5 Update

- Local uv development now resolves `keble-segmenting 0.4.8`, matching the
  display-critical auto-segment action contract consumed by backend and
  frontend lazy axis selection.
- Runtime positioning behavior is unchanged from `0.7.4`; this patch keeps the
  package contract tests and bundled segmenting wheel aligned with the current
  line.

## Version 0.7.4 Update

- Positioning view-detail aggregation now explicitly opts into segmenting
  synthetic status cells after reducing the grid detail to display dimensions.
- Full-grid prompt/admin reads stay guarded by the segmenting default and do
  not build cartesian status cells for every grid dimension.
- Local uv development now resolves `keble-segmenting 0.4.7`.

## Version 0.7.3 Update

- Local uv development now resolves `keble-segmenting 0.4.5`, matching the
  backend current-line preset-mask runtime.
- The package dependency floor is raised to `keble-segmenting >=0.4.5,<1` so
  positioning tests exercise the same preset-role and grid-scoped mask contract
  consumed by backend `2.5.4`.
- Historical local `keble_segmenting` wheel artifacts older than `0.4.5` were
  removed after the source, lockfile, and docs moved to the current wheel.

## Version 0.7.2 Update

- Positioning view defaults now treat historical first-N grid-order views as
  replaceable auto defaults.
- When preset roles exist, default display axes resolve pricing first, then
  features/functionality, then scene/use-case, with grid order as the final
  fill.
- Non-default saved user views remain authoritative and keep their saved axis
  order.

## Version 0.7.1 Update

- Package contract tests now derive the current version from `pyproject.toml`
  instead of pinning a stale historical release value.
- `mutate_positioning_task_workspace` keeps name/description configurable but
  always requires approval because it creates durable tasks and relations.

## Version 0.7.0 Update

- Positioning workspace action/event contracts now live in
  `keble_positioning.schemas.workspace_actions` instead of backend execution
  modules.
- `PositioningTaskWorkspaceActionedResult` reuses generic `keble-task`
  `TaskActionCreatedTask` and `TaskActionCreatedRelation` payloads, so created
  child tasks and relation metadata share one canonical DTO.
- `keble_positioning.agent.registry.register(...)` registers
  `mutate_positioning_task_workspace` only when a backend execution handler is
  supplied; the package owns tool schema/approval metadata, while backend owns
  task spawning and SSE publishing.

## Version 0.6.0 Update

- Reduced child positionings now persist typed `item_source_scopes` and read
  source-owned item records on demand instead of copying selected records into
  the child row.
- `PositioningClient.avalidate_item_source_scopes(...)`,
  `alist_scoped_item_records(...)`, `alist_scoped_item_relationships(...)`, and
  `aget_positioning_items_data(...)` are the canonical map-only read surface.
- `SEED_ONLY` writes no child item records or relationships; `SEED_AND_DISCOVER`
  writes only newly discovered fresh child records.
- Mapped viewport rows still use `source_positioning_id`; reduced children use
  `item_source_scopes`, so the two source mechanisms stay separate.

## Version 0.4.14 Update

- Scoped carryover now fails fast when a selected source item key is missing from
  the source positioning, rather than silently falling back to fresh items.
- Missing scope diagnostics report the source positioning
  and stale selected key so backend/chat callers can surface a refresh/retry
  boundary instead of creating a partial reduced child.

## Version 0.4.12 Update

- Removed old positioning runtime-field cleanup and index-upgrade helpers after
  the task-root hard break; current CRUD only creates canonical indexes.
- Keeps the current task-room bridge boundary: `PositioningAgentContext` carries
  `root_task_id` and `allowed_grid_ids`, while segmenting mutations target
  `Actions.grid_id`.

## Version 0.4.11 Update

- Invalid-parameter diagnostics now pass typed primitive strings into
  `keble-exceptions` instead of dict payloads.
- Mapped-row mutation rejection and relationship endpoint validation keep the
  same user-facing context while satisfying Pylance/Pyright argument typing.

## Version 0.4.10 Update

- `PositioningAgentContext` is now task-room scoped: `owner`, `language`,
  `root_task_id`, and `allowed_grid_ids`.
- `mutate_segmenting` validates `Actions.grid_id` against `allowed_grid_ids`
  and delegates the whole canonical `Actions` payload.
- `PositioningClient.aapply_segmenting_actions(...)` resolves the source
  positioning from `payload.grid_id` and owner; callers no longer pass
  `positioning_id`, `grid_id`, and `actions` separately.
- Backend enrichment can use `aresolve_positioning_context_by_task(...)` and
  `aget_source_positioning_by_grid_id(...)`.
- `aget_grid_for_agent(...)` now requires `compare_dimension_key` and builds
  `GridAgentContextRequest`.

## Version 0.4.9 Update

- `aapply_segmenting_actions(...)` now requires explicit `grid_id` and forwards
  one canonical `Actions(grid_id=...)` payload into `keble-segmenting`.
- Positioning no longer builds or passes `SegmentingUxContext`; workspace
  selection stays outside the bridge and segmenting execution targets only the
  explicit grid/action payload.
- `aapply_segmenting_actions(...)` now inherits nested
  `SegmentingAgentDeps.segmenting.event_callbacks` when callers do not provide
  explicit callbacks.
- Backend composite deps can pass through positioning into segmenting without
  dropping room SSE callbacks.
- Grouped followers remain metadata-only; positioning still does not copy
  source/group segmenting rows to follower item keys.
- `PositionableItemLoaded.to_cell_display(...)` and
  `PositionableItemsByRel.to_cell_display(...)` now delegate display projection
  to the provider item class. Positioning groups records and preserves item
  identity, but it does not parse commerce payloads into UI summaries.
- `CellDisplay` is display-only (`description` / `images`); complete selected
  item identity comes from segmenting aggregate `item_keys`.

## Design Direction

The current rewrite is bridge-first:

1. `keble-segmenting` owns action execution, progress, and grid mutation.
2. `keble-positioning` owns only bridge-specific persistence and conversion:
   - positioning objects and views,
   - positionable item records,
   - positionable relationship records,
   - fresh-item callback flows,
   - grouped representative selection with metadata-only followers.
3. This package no longer exposes positioning-owned agentic payloads, local runtime status models, or task/background orchestration helpers.

Queued auto-segment fanout stays backend-owned. Positioning forwards optional
backend scheduler/context into `keble-segmenting`; grouped followers remain
metadata-only and are not copied into segmenting result rows after workers finish.
Room/SSE transports should stream direct package `AgenticActionEvent` JSON.
Positioning should not create backend-specific room event wrappers. View events
use uppercase package-owned `action_type` values on the shared helper event
shape.
Positioning now emits direct `UPSERT_ITEM_RECORDS` and
`UPSERT_ITEM_RELATIONSHIPS` events for fresh-item CRUD batches, and forwards
request-scoped callbacks into segmenting action execution so segmenting
mutation events can reach the same task-root SSE room.
In `0.4.8`, positioning also returns and emits `PositioningViewDetailed` with
the full grid `dimensions` / `masks` plus current-view `aggregated_cells`, so
production rooms can switch axes locally while reading only the active view
matrix. Room stores can patch the visible node without a backend wrapper.
Downstream TypeScript consumers should use `keble-core 0.1.33+`
`TaskWorkspaceEvent.build(...)` for these direct package payloads instead of
frontend-local unknown payload normalization.

## Public Package Surface

The package root exports the slim bridge contract:

```python
from keble_positioning import (
    PositionableItemLoaded,
    PositionableItemsByRel,
    PositioningAgentContext,
    PositioningAgentDeps,
    PositioningBase,
    PositioningBootstrapResult,
    PositioningClient,
    PositioningDependencies,
    PositioningMutationToolsConfig,
    PositioningMongoObject,
    PositioningTaskMetadata,
    PositioningUpdate,
    PositioningViewBase,
    PositioningViewDetailed,
    PositioningViewMongoObject,
    PositioningViewUpdate,
    register_mutation_tools,
)
```

The main client surface is now:

1. persisted positioning CRUD
2. persisted view CRUD
3. slim upstream bootstrap via `PositioningTaskMetadata`, `PositioningBootstrapResult`, and `abootstrap_positioning(...)`
4. thin upstream task wrapper via `atask_handler(...)`
5. fresh-item loading / next-page loading
6. viewport-map creation via `acreate_mapped_positioning(...)`
7. canonical `aapply_segmenting_actions(...)`
8. explicit `aget_segmenting_progress(...)`
9. explicit `ainterrupt_segmenting(...)`
10. canonical `aget_view_detailed(...)`

The package still does not own background orchestration or runtime status recovery.
The new bootstrap surface only covers the initial grid + positioning shell, the first
fresh-item load, and the first dimension-discovery pass.
Bootstrap is now retry-safe for one task id: if a previous attempt already created the
positioning shell, `abootstrap_positioning(...)` reloads that persisted positioning/grid
pair instead of creating a second shell.
When `progress_task` is present on the request-scoped deps, bootstrap now emits
randomized top-level stage messages plus nested fresh-load subtasks so the parent
task UI can show visible movement without adding a second event system. The
in-progress copy is intentionally varied and more human-feeling, while terminal
success and stop messages remain literal and stable for callers.
The active bootstrap discovery stage and canonical segmenting action batches now
also forward the available `progress_task` into `keble-segmenting` so upstream
runtime messages can keep flowing through the same task tree.

## Bootstrap Storage Contract

The persisted bridge contract is intentionally short:

1. one upstream `task_id` owns one positioning shell
2. one positioning shell points at one segmenting `grid_id`
3. bootstrap retries reuse that existing shell instead of creating duplicates
4. resolved `search_terms` are persisted on task metadata and callback pagination state, while positioning rows do not persist `search_terms`
5. mapped positioning rows use their own `task_id` and view, share the source `grid_id`, and point at source-owned items through `source_positioning_id`
6. mapped positioning rows are viewport-only for mutations; `aapply_segmenting_actions(...)` rejects them so source dimensions/results cannot diverge by accident

Mapped positioning rows are viewport-only in this line. They can read source
items/relationships and shared segmenting results, but fresh item loading and
next-page pagination must run against the source positioning row.

```python
mapped_positioning = await positioning_client.acreate_mapped_positioning(
    amongo,
    owner=owner,
    task_id=mapped_task.id,
    source_positioning_id=source_positioning.id,
    view_owner=owner,
    display_dimension_ids=[dimension_id],
)

data = await positioning_client.aget_positioning_data(
    amongo,
    positioning_id=mapped_positioning.id,
    positioning_owner=owner,
)
```

## Upstream Task Wrapper

Use the upstream task metadata plus the thin task wrapper when the parent backend
already owns task scheduling and completion:

```python
from keble_positioning import PositioningTaskMetadata

task_handler_metadata = PositioningTaskMetadata(
    positioning_context=payload.positioning_context,
    search_terms=payload.search_terms,
    language=language,
    marketplace=payload.marketplace,
    entity_type=payload.entity_type,
    name=payload.name,
    positioning_metadata={},
)

await positioning_client.atask_handler(request=request)
```

`request.metadata` should serialize the `PositioningTaskMetadata` payload. The
positioning package still does not own background orchestration, runtime status
recovery, or backend-specific Redis namespace setup.
When the parent backend resolves prompt-to-model search keywords, it should pass
those typed `search_terms` here so bootstrap can start with the intended
retrieval list. Later rounds may supply a different list, and next-page
continuity is carried by callback metadata rather than by the positioning row.

## Canonical Write Bridge

Use the direct segmenting bridge instead of any positioning-owned action wrapper:

```python
from keble_helpers import Language
from keble_helpers import AgenticActionWarningLevel
from keble_segmenting.schemas import Action, ActionedResults, Actions


async def apply_actions(
    *,
    positioning_client: PositioningClient,
    owner: str,
    db_deps,
    grid_id,
    actions: list[Action],
) -> ActionedResults:
    return await positioning_client.aapply_segmenting_actions(
        owner=owner,
        db_deps=db_deps,
        language=Language.ENGLISH,
        payload=Actions.build(
            message="Apply positioning segmenting actions.",
            warning_level=AgenticActionWarningLevel.MUTATION,
            grid_id=grid_id,
            actions=actions,
        ),
    )
```

`PositioningClient` prepares the grouped representative loader and delegates the canonical `Actions` payload to `keble-segmenting`. Grouped follower keys are kept in group metadata only; missing follower result rows are expected and should not be repaired.

## Agent Tool Registration

Positioning owns the pydantic-ai registrar for positioning-scoped segmenting
mutations. Backend should register this package tool instead of defining a
manual duplicate in backend chat code.

```python
from keble_positioning.agent import PositioningAgentDeps, register_mutation_tools

agent = Agent[PositioningAgentDeps, Any](...)

register_mutation_tools(
    agent,
    positioning_client=positioning_client,
    enabled=True,
)
```

Deps shape:
- `PositioningAgentDeps` inherits `keble_db.AgentDbDeps`; Mongo/Redis are not separate tool args.
- Positioning runtime state is under `ctx.deps.positioning`.
- The tool delegates to `PositioningClient.aapply_segmenting_actions(...)`, so source-positioning mutation guards and grouped-loader behavior stay package-owned.
- Backend should omit mapped/view-only grids from `allowed_grid_ids`; they must
  not mutate shared source dimensions/results.

## Canonical Read Surface

`PositioningViewDetailed` is now a pure read model:

1. `view`
2. `positioning`
3. `grid`
4. `dimensions`
5. `aggregated_cells`

Live segmenting progress is not embedded in the room payload anymore. Call `aget_segmenting_progress(...)` explicitly when the caller needs exact-key runtime progress.

## Parent Repo Guidance

`[tool.uv.sources]` paths in this repo are parent-relative to this package directory. They are not inherited from a parent application repo:

```toml
[tool.uv.sources]
keble-segmenting = { path = "deps/keble_segmenting-0.6.1-py3-none-any.whl" }
keble-task = { path = "deps/keble_task-2.4.11-py3-none-any.whl" }
```

## Validation Commands

Use `uv` commands only:

1. `uv run python -c "import keble_segmenting"`
2. `uv run python -c "import keble_positioning"`
3. `uv run pytest tests -q`
4. `uv run pytest -m "not live" tests -q`
5. `uv run pytest -m live tests -q`
6. `uv run python tests/live/refresh_keepa_green_alien_plush_cache.py`
7. `uv lock`
8. `uv sync`

The default `pytest` run is intentionally strict and comprehensive:

1. it includes the live Keepa plus env-backed Azure/OpenAI tests under `tests/live`
2. it fails fast when `tests/.env`, Mongo, Redis, Keepa, or text-model config is missing
3. it keeps the refresh script as the only write path for tracked live cache files under `tests/asset/`
## 0.5.0 Preset Dimension Defaults And Child Discovery

`keble-positioning 0.5.0` consumes `keble-segmenting 0.2.0` and the new preset
dimension contract. View-detail defaults now prefer pricing as the row axis,
features/functionality as the column axis, scene/use-case as the next column
fallback, and then the existing grid order.

Reduced child positioning tasks default to `SEED_ONLY`; fresh product discovery
is an explicit `SEED_AND_DISCOVER` mode. This preserves copied selected item
records and in-scope relationships for child grids while preventing accidental
fresh expansion unless the caller requests it.

## 0.6.1 Chained Map-Only Source Scopes

`keble-positioning 0.6.1` resolves nested reduced-child item scopes through the
original source positionings before reads or bootstrap persistence. A child made
from a map-only child therefore reads the root/source item records selected by
the parent scope, not the intermediate child positioning that intentionally owns
no copied item records.

Use `PositioningClient.aresolve_item_source_scopes(...)` before persisting
reduced-child metadata, and use `aget_positioning_items_data(...)` for explicit
item payload reads. The seed-copy workflow remains removed.

## 0.6.2 Mapped Viewport Scope Alias

`keble-positioning 0.6.2` keeps map-only reduced children package-owned by
teaching `aresolve_item_source_scopes(...)` to treat mapped viewport rows as
aliases to their canonical `source_positioning_id`. Reducing from a mapped
viewport now reads the source-owned item records instead of rejecting the mapped
row as a non-source positioning.

## 0.8.0 Terminal Segmenting Consumption

`keble-positioning 0.8.0` raises its `keble-segmenting` floor to `>=0.5.0,<1`
and consumes the terminal omission aggregate contract. View-detail reads should
continue to call `aget_view_detailed(...)` with display axes narrowed before
synthetic status cells are requested; omitted segmenting rows are handled by the
segmenting read model and require no positioning-side workaround.

## 0.9.0 Multi-Select Segmenting Consumption

`keble-positioning 0.9.0` raises its `keble-segmenting` floor to
`>=0.6.0,<1`. The positioning view/detail API preserves the aggregate placement
counts returned by segmenting so multi-select axes can display one source item in
every selected option-cell combination without copying result rows.

## 0.9.1 Segmenting Cleanup Consumption

`keble-positioning 0.9.1` raises its local wheel source and dependency floor to
`keble-segmenting >=0.6.1,<1`. This keeps current package tests and downstream
backend installs on the release where stale singular-result helper residue was
removed.

## 0.9.2 Owner-Type Metadata Mirror

`keble-positioning 0.9.2` adds optional `owner_type` to
`PositioningTaskMetadata`. Backend queue envelopes can now carry the same owner
classification used by seller-profile context without adding a separate
positioning-side profile schema. The field is optional so already queued or
historical task metadata remains loadable.
