# Define a semantic domain

This recipe creates an organization-owned process language and reusable audit
trait that compose with One without becoming `one.*` meaning.

The `.one` and Rust APIs below are illustrative end-product syntax.

## 1. Define the domain package

```one
semantic acme.audit
    domain one.trait@1
    use acme.audit.contracts@1 as audit_contracts

    trait Audited@1
        target: declaration implements one.semantic#StateTransition@1
        retention: CalendarPeriod
        contributes: audit_contracts.AuditRequirementContribution

semantic acme.process
    domain one.semantic.domain@1
    use one.data.SubjectScopeValue@1
    use one.contracts.StableKeyValue@1

    domain Process@1
        extends one.semantic@1
        use acme.audit.Audited@1
        use one.data@1 only Key, Scope
        use one.contracts.Length@1

        kind Entity@1
            posture: definition
            members: named_fields
            exposes: one.semantic#FieldContainer@1

        kind Transition@1
            posture: definition
            from: StageRef
            to: StageRef
            deadline: DurationConstraint?
            exposes: one.semantic#StateTransition@1

        normalizer ProcessTraitNormalizer@1

        impl Key
            for Entity@1.field<T>
            where T implements StableKeyValue
            normalize_with: ProcessTraitNormalizer

        impl Scope
            for Entity@1.field<T>
            where T implements SubjectScopeValue
            normalize_with: ProcessTraitNormalizer

        impl Audited
            for Transition@1
            normalize_with: ProcessTraitNormalizer
```

`extends` establishes one compatibility lineage. `use` composes reusable
meaning and exports a closed public name table. The exact trait implementations
make imported traits applicable to Acme's own declaration kinds; import alone
would not.

## 2. Author with the domain

```one
semantic acme.shipping
    domain acme.process@1

    type TenantId@1 = Text @Length(1..=64)
    type ShipmentId@1 = Text @Length(1..=64)

    enum ShipmentStage@1
        ready
        in_transit

    entity Shipment@1
        tenant: TenantId @Key @Scope
        id: ShipmentId @Key
        label: Text @Length(1..=128)

    transition Dispatch@1
        from: ShipmentStage.ready
        to: ShipmentStage.in_transit
        deadline: <= 30s
        @Audited(retention: 7y)
```

`entity`, `transition`, and their normalization belong to Acme. `Text`,
`@Length`, `@Key`, `@Scope`, time quantities, and global composition laws keep
their original One owners. The authored submission remains untrusted until
every applicable owner validates its contribution.

## 3. Normalize at the owner boundary

```rust,ignore
impl DomainNormalizer<ProcessSubmission> for ProcessNormalizer {
    type Output = ProcessDescriptor;

    fn normalize(input: ProcessSubmission) -> Result<Self::Output, DomainFault> {
        ProcessDescriptor::validate(input)
    }
}
```

Lower systems consume `ProcessDescriptor`, never parser tokens or authored
field ordering. A custom normalizer is capability-empty and returns only an
untrusted bounded proposal; it cannot mint trusted Knowledge records.

## 4. Report mapping loss

```text
mapping acme.process#transition_to_history@1
preserved transition identity, subject, and audit retention
defaulted observation independence = same_process
lost presentation label
receipt projection:sha256:31a8…
```

Directional loss is explicit and never implies a reverse mapping.

See [domains and traits](/one/authoring/domains-and-traits) and
[semantic domains](/one/platform/semantic-domains).
