# Agent-Safe Unique Inventory Spec v0.1

Status: draft teaching specification, reviewed 2026-07-30. It is not an
adopted industry standard and does not claim conformance with a commerce
platform. Text is CC BY 4.0. The JSON Schema and examples are provided under
the same license. No DOI has been assigned.

## Purpose and boundary

This profile describes the minimum facts needed to represent one physical item
and one current offer without silently turning the item into generic,
replaceable stock. A record that validates is internally consistent; validation
does not grant platform access, prove product eligibility, synchronize a
channel, reserve inventory, authorize a buyer, or guarantee retrieval.

## Record relationships

```text
product/model 1 ─── n physical item 1 ─── n offer version
                         │                       │
                         └── condition evidence └── price, availability, policy
```

`physical_item_id` remains stable for the owned object. `product_id` can group
objects of the same model. `offer_id` identifies sale terms and may change on a
true relist. Channel listing IDs belong in an extension or mapping and must not
replace the physical item ID.

When duplicate object records are merged, the survivor keeps its canonical URL
and the retired record moves to `aliases` and resolves to `redirect_target`.
The redirect represents identity continuity, not a relist. A relist preserves
the physical item ID and advances the offer identity or lifecycle version.

## Required field dictionary

| Path | Type | Rule |
| --- | --- | --- |
| `physical_item_id` | string | Stable identifier for exactly one owned unit. |
| `product_id` | string | Model or product identity; it may be shared by multiple units. |
| `offer_id` | string | Stable identity for the current commercial offer. |
| `title` | string | Factual title for the exact item; do not hide a material defect. |
| `canonical_url` | URI | Public destination for this item or its truthful tombstone. |
| `aliases[]` | URI array, optional | Retired object URLs that resolve to this record. |
| `redirect_target` | URI, optional | Surviving object URL when this record is an alias. |
| `channel_listings[]` | object array, optional | Channel, listing ID, and URL; never object identity. |
| `images[]` | URI array | At least one image of the exact unit, not representative stock. |
| `condition.label` | string | Normalized seller condition. |
| `condition.notes` | string | Item-specific condition narrative. |
| `condition.inspected_at` | date | Date the exact unit was inspected. |
| `condition.evidence_urls[]` | URI array | Exact-item photos or other inspectable evidence. |
| `offer.price_minor` | integer | Price in the currency’s minor unit; avoids decimal ambiguity. |
| `offer.currency` | string | Three uppercase ISO-style currency letters. |
| `offer.quantity` | integer | `1` only while available/reserved; `0` when sold/withdrawn. |
| `offer.availability` | enum | `available`, `reserved`, `sold`, or `withdrawn`. |
| `offer.observed_at` | date-time | When price and availability were observed at the source. |
| `offer.seller_url` | URI | Public seller identity or profile. |
| `offer.shipping_policy_url` | URI | Resolvable shipping policy. |
| `offer.returns_policy_url` | URI | Resolvable return policy. |
| `lifecycle.version` | string | Source version or conditional-update token. |
| `lifecycle.state` | enum | Must agree with offer availability. |
| `lifecycle.updated_at` | date-time | Must not precede `offer.observed_at`. |

## State machine

```text
available ── reserve ──> reserved ── accept order ──> sold
    │                       │
    │                       └── release ────────────> available
    └── withdraw ──────────────────────────────────> withdrawn
```

`sold` and `withdrawn` are terminal for the current offer. A merchant may
create a new offer only after verifying that the same object is still owned and
available. Relisting must advance the version and cannot erase the history
needed to distinguish a correction from a duplicate live offer.

## Stable validation rules

- `ASUI-SHAPE-REQUIRED`: reject a record missing any required top-level group.
- `ASUI-CONDITION-EVIDENCE`: reject empty condition notes or evidence for a
  unique item.
- `ASUI-AVAILABILITY-QUANTITY`: `available` requires quantity 1; `sold` and
  `withdrawn` require quantity 0.
- `ASUI-LIFECYCLE-AGREEMENT`: lifecycle and offer states must agree.
- `ASUI-LIFECYCLE-TIME`: lifecycle update time cannot precede the offer
  observation.

The downloadable JSON Schema checks field shape. The checked-in validator adds
the cross-field rules above and tests both accepted and rejected fixtures.

The versioned JSON-LD context maps fields to Schema.org where a faithful term
exists and records the gaps where ASUI terms are necessary. The conformance
statement is self-declared and is not certification or platform approval.

## Current Instica mapping

The profile is vendor neutral. Before an Instica implementation claims support,
map each field to the production inventory contract and verify it in code and a
real export. A proposed mapping is deliberately labeled rather than presented
as shipped:

| Profile concept | Mapping status |
| --- | --- |
| Physical item ID | Must map to the stable Instica inventory-item identifier. |
| Product/model ID | Optional grouping needs product-contract verification. |
| Offer ID and channel IDs | Needs an explicit offer/listing relationship review. |
| Exact-item images and condition | Verify field ownership and public URL behavior. |
| Price, currency, quantity, availability | Verify source-of-truth and update timing. |
| Version and lifecycle timestamp | Confirm conditional-update or equivalent semantics. |
| Policy and seller URLs | Confirm public, channel-appropriate URLs. |

Until that mapping review is complete, this artifact is a teaching and exchange
proposal, not a declaration that Instica exports v0.1.

The neutral schema may later be projected into vendor-specific protocol
capabilities. The sibling strategy proposes UCP capabilities under a
`com.instica.*` namespace, but those capabilities are not claimed as shipped.
If implemented, they must use this field dictionary, preserve graceful
degradation for clients that do not negotiate the extension, and publish their
own conformance evidence. Neither the proposal nor this teaching artifact is
evidence that the other is correct or live.

## Operator checklist

1. Validate the full record and preserve the result with rule IDs.
2. Confirm images and condition evidence belong to the exact physical item.
3. Simulate reserve, release, sale, and withdrawal transitions.
4. Send the changed state through the documented channel path.
5. Verify every public surface independently and record elapsed time.
6. Retain a truthful tombstone or redirect after sale.
7. Stop or roll back when availability, price, identity, or policy conflicts.

Corrections and version proposals go through the Instica editorial-policy
contact or the public repository issue tracker at
https://github.com/pinestraw/instica-marketing-web/issues. Version 0.x is
unstable; consumers should pin the exact schema URL and review the downloadable
change record before updating. No DOI exists yet; do not cite one.
