core/docs/identity_packs.md
Shay 310aed9ff0
chore: Refactor CLI and Governance Anchors (#926)
* docs: consolidate governance anchors and clean up test registries

* refactor(cli): decompose cli into dedicated modules

* test: fix broken test baselines and formatting

* docs: add domain boundary READMEs for governance anchors

* test: update baseline for determination lane

* test: fix capability_pass expectation

* test: fix CORE_SHOWCASE_SKIP_BUDGET enforcement

* chore: cleanup CLI extraction and unreachable code
2026-07-03 12:34:56 -07:00

208 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Identity Packs — Reference
**Status:** Operational reference doctrine. Update when pack format, loader contract, or CLI flag semantics change.
**Last updated:** 2026-05-17
**Companion docs:** [`adr/ADR-0027-identity-packs.md`](adr/ADR-0027-identity-packs.md), [`teaching_order.md`](teaching_order.md), [`specs/runtime_contracts.md`](specs/runtime_contracts.md)
## What an identity pack is
An identity pack is the on-disk, content-addressed representation of an `IdentityManifold`. At runtime startup, CORE loads exactly one identity pack and uses it to construct the manifold that drives `PersonaMotor.from_identity_manifold()` and `IdentityCheck`. Replacing the pack replaces the model's identity surface without touching code.
Identity packs sit alongside language packs in the trust hierarchy:
- **Language packs** (`packs/en/`, `packs/grc/`, `packs/he/`, …) — what CORE *speaks*.
- **Identity packs** (`packs/identity/<pack_id>.json`) — *who* CORE is while speaking.
- **Safety packs** (future, `packs/identity_safety/`) — what CORE will *never* be, regardless of identity pack.
## Pack format (v1)
A single JSON file. Strings, ints, bools, lists, dicts only — same canonical-JSON discipline as the formation pipeline (no floats embedded in identifying fields; numeric direction vectors are floats but their canonical position in the file is fixed).
```json
{
"pack_id": "default_general_v1",
"version": "1.0.0",
"description": "Balanced general identity. Default shipping pack.",
"schema_version": "1.0.0",
"mastery_report_sha256": "",
"alignment_threshold": 0.45,
"boundary_ids": [
"no_fabricated_source",
"no_hot_path_repair"
],
"value_axes": [
{
"axis_id": "truthfulness",
"name": "truthfulness",
"direction": [1.0, 0.0, 0.0],
"weight": 1.0,
"theological_note": "Truth is treated as a fixed value axis, not a prompt preference."
},
{
"axis_id": "coherence",
"name": "coherence",
"direction": [0.0, 1.0, 0.0],
"weight": 1.0,
"theological_note": "Operations must preserve field coherence under propagation."
},
{
"axis_id": "reverence",
"name": "reverence",
"direction": [0.0, 0.0, 1.0],
"weight": 1.0,
"theological_note": "Depth-language handling remains bounded by source structure."
}
]
}
```
### Field semantics
| Field | Required | Meaning |
|---|---|---|
| `pack_id` | yes | Unique identifier. Convention: `<slug>_v<major>`. |
| `version` | yes | Semver. Bumping `major` produces a new `pack_id`. |
| `description` | yes | Human-facing one-liner. Surfaces in `core pulse --list-identity-packs`. |
| `schema_version` | yes | Format version. Currently `"1.0.0"`. |
| `surface_preferences` | no | Pack-supplied surface hedge / claim-strength shaping (ADR-0028). Defaults preserve pre-ADR behavior. See §"Surface preferences" below. |
| `mastery_report_sha256` | no | SHA of the companion `<pack_id>.mastery_report.json`. Empty for unratified development packs; production deployments refuse to load packs with empty values. |
| `alignment_threshold` | yes | Float in [0, 1]. Passed to `IdentityManifold.alignment_threshold`. |
| `boundary_ids` | yes | List of boundary identifiers. Mirrors `IdentityManifold.boundary_ids`. |
| `value_axes` | yes | List of ≥ 1 axes. Each has: `axis_id`, `name`, `direction` (list of 3 floats in [-1, 1]), `weight` (float ≥ 0), `theological_note`. |
### Axis-specific hedge phrases (ADR-0031)
Optional sub-block inside `surface_preferences` that lets the assembler call out *which* axis is deviating when it hedges. When `IdentityScore.deviation_axes` names an axis and the pack supplies an `axis_hedges` entry for that axis, the lex-smallest match is used instead of the generic `preferred_hedge_*`:
```json
"axis_hedges": {
"truthfulness": {
"strong": "Evidence is thin that",
"soft": "It is hard to confirm that",
"qualifier": "Where evidence is partial,"
},
"coherence": { "strong": "...", "soft": "...", "qualifier": "..." },
"reverence": { "strong": "...", "soft": "...", "qualifier": "..." }
}
```
Each axis entry must supply `strong`, `soft`, and `qualifier` phrases (length 164). When no deviating axis matches an `axis_hedges` entry, the generic phrases from §"Surface preferences" fire. Depth languages (Hebrew, Koine Greek) ignore `axis_hedges` at v1 and continue to use the canonical phrases from [ADR-0030](adr/ADR-0030-depth-language-hedge.md).
### Surface preferences (ADR-0028)
Optional block driving the assembler's hedge and claim-strength decisions:
```json
"surface_preferences": {
"hedge_threshold_strong": 0.40,
"hedge_threshold_soft": 0.50,
"preferred_hedge_strong": "It seems that",
"preferred_hedge_soft": "Perhaps",
"claim_strength": "balanced",
"qualified_band_high": 0.75,
"preferred_qualifier": "In some cases,"
}
```
Bands (in descending hedge strength):
1. `alignment < hedge_threshold_strong` → prepend `preferred_hedge_strong`.
2. `alignment < hedge_threshold_soft` → prepend `preferred_hedge_soft`.
3. `hedge_threshold_soft <= alignment < qualified_band_high` and `claim_strength == "qualified"` → prepend `preferred_qualifier`.
4. Otherwise leave the assertion bare.
Threshold ordering required: `hedge_threshold_strong <= hedge_threshold_soft <= qualified_band_high`. Loader enforces this.
`claim_strength` must be one of `{"balanced", "qualified", "affirmative"}`. `"balanced"` and `"affirmative"` skip the marginal-band qualifier; only `"qualified"` triggers it.
### Loader bounds (enforced)
- `len(value_axes) >= 1` — empty axes are refused.
- Each `direction` must have length 3 and each component in `[-1.0, 1.0]`.
- `weight` must be in `[0.0, 10.0]` — prevents a single axis from dominating arbitrarily.
- `alignment_threshold` must be in `[0.0, 1.0]`.
- `axis_id` values must be unique within a pack.
- Production mode requires `mastery_report_sha256 != ""` and the companion report's self-seal to verify; development mode (`CORE_ALLOW_UNRATIFIED_IDENTITY=1`) bypasses both.
## Loader contract
```python
from packs.identity.loader import load_identity_manifold
manifold = load_identity_manifold(
pack_id="default_general_v1", # required
search_paths=None, # default: ["./packs/identity"]
require_ratified=True, # production default
)
```
Returns an `IdentityManifold` (from `core/physics/identity.py`). Raises `IdentityPackError` on missing pack, malformed JSON, bound violations, or unverified self-seal in production mode.
The loader is path-aware: deployments may supply `search_paths=("/srv/myapp/packs/identity", "./packs/identity")` so a robotics or app builder can ship overlay packs without touching CORE's own packs directory.
## CLI usage
```bash
core chat
# Loads the default identity pack (currently default_general_v1).
core chat --identity precision_first_v1
# Loads a specific pack. Pack must exist on the loader's search paths.
core chat --list-identity-packs
# Lists discoverable packs with description + ratification status.
# Short-circuits before the REPL launches.
core chat --list-identity-packs --json
# Same listing as machine-readable JSON (pack_id, version, description,
# ratified, path).
core chat --identity generosity_first_v1
# A different specialization on the chat surface.
CORE_DEFAULT_IDENTITY_PACK=precision_first_v1 core pulse "..."
# Environment override of the default. Takes precedence over the
# core/config.py constant; --identity on the command line takes
# precedence over the env var.
```
## Shipping packs (v1)
| Pack id | Role | Notes |
|---|---|---|
| `default_general_v1` | Ship default. Balanced. | Encodes the *exact* three axes (`truthfulness`, `coherence`, `reverence`) previously hardcoded in `chat/runtime.py`. Behavioral no-op vs. pre-ADR runtime. ADR-0028 surface_preferences: balanced; hedge thresholds 0.40/0.50/0.75. ADR-0031 axis_hedges: "Evidence is thin that" / "This does not yet cohere:" / "Reports suggest". Ratified: `2ab7d469013509ba5030313ca9a609a443d0716e3ddcc5596f59858ce054f5d3`. |
| `precision_first_v1` | Specialization example A. | Boosts `truthfulness` weight, narrows reverence direction. Surface: hedges sooner (0.55/0.70/0.85), uses "Arguably,"/"In some cases,"/"Under certain conditions,"; claim_strength=qualified. ADR-0031 axis_hedges: "The evidence does not support that" / "This contradicts what is established:" / "Source attestation is weak:". Source: `evals/identity_divergence/axes/axis_a.yaml`. Ratified: `78aa1e6a68a35c2c8576b6196a52d421b94f6d11e006128986902a4fd08679af`. |
| `generosity_first_v1` | Specialization example B. | Boosts `coherence` weight, broadens reverence direction. Surface: hedges later (0.20/0.30/0.50); claim_strength=affirmative. ADR-0031 axis_hedges: "Some hold that" / "There is a thread connecting this:" / "It is reported that". Source: `evals/identity_divergence/axes/axis_b.yaml`. Ratified: `511f1ce20edd4266239da61443bfc93473a5433f20bfee6692a25a03073dc933`. |
Each ratified pack ships alongside a `<pack_id>.mastery_report.json` companion file. The loader, in production mode, verifies the companion's self-seal and cross-checks its `report_sha256` against the pack's `mastery_report_sha256`. To re-ratify after editing a pack's axes, run `python scripts/ratify_identity_packs.py` (idempotent — re-running on already-current packs is a no-op).
## Authoring a new identity pack (robotics / personalization / creative tools)
1. **Author the SubjectSpec.** Use `core formation new <subject_id>` to scaffold; edit to declare the pack's intent and identity axis constraints.
2. **Hand-author the candidate axes.** Use the `identity_anchor` template's expected input shape: `concepts` are axes (with `definition` = behavioral commitment), `counters` are override-attempt probes the pack must refuse.
3. **Ratify through formation.** Render → compose → compile → run → ratify. Produces a signed `MasteryReport`.
4. **Promote.** Promotion goes through `teaching/review.py`'s reviewed-apply path. The promote step writes both `<pack_id>.json` and `<pack_id>.mastery_report.json` to `packs/identity/`.
5. **Deploy.** The pack is now selectable by `--identity <pack_id>`. Distribute alongside your deployment's other artifacts.
### Anti-patterns
- **Don't author identity packs by hand-editing `packs/identity/`.** The runtime never writes there; neither should authors. All packs flow through formation so audit trails are intact.
- **Don't ship unratified packs (empty `mastery_report_sha256`) in production.** The loader's `require_ratified` flag exists to refuse them.
- **Don't try to override `boundary_ids` to weaken refusal.** Boundaries are the immutable contract; if your identity pack omits expected boundaries, the runtime refuses to load it.
- **Don't try to express safety constraints in an identity pack.** Safety axes belong in the (future) safety pack, always-loaded and never-replaceable.
## Known limits (read before designing around)
1. ~~**Identity does not yet visibly differentiate articulation at the realizer.**~~ **Closed by [ADR-0028](adr/ADR-0028-identity-surface-wiring.md) + [ADR-0030](adr/ADR-0030-depth-language-hedge.md) (2026-05-17).** Pack `surface_preferences` now flow into the English, Hebrew, and Koine Greek assemblers. `core chat --identity precision_first_v1 "Q"` produces a visibly different surface than the default pack on the same prompt at the same alignment, *across all three foundational languages*. Per-pack depth-language phrase overrides remain a future concern (today's depth-language hedge phrases are canonical defaults in `generate/surface.py::_DEPTH_HEDGE_PHRASES`).
2. **One pack at a time.** Multi-pack overlays (`--identity general,domain_medical`) are deferred to a follow-up ADR.
3. **No language-specific identity yet.** Packs are language-neutral. Per-language identity is a future concern.
4. **Safety axes are still in `chat/runtime.py`.** Once the safety pack ADR lands, safety boundaries will move out of `boundary_ids` and into a separately-loaded safety pack.
## Cross-reference index
- Pack format spec: this doc §"Pack format (v1)".
- Loader contract: this doc §"Loader contract".
- Decision record: [ADR-0027](adr/ADR-0027-identity-packs.md).
- Teaching-order placement: [`teaching_order.md`](teaching_order.md) §"The Five-Layer Ordering Rule" Layer 1.
- Identity-divergence eval: `evals/identity_divergence/contract.md`.
- The geometric identity primitives: `core/physics/identity.py` (ADR-0010 implicit).
- The formation template that ratifies packs: `formation/templates/identity_anchor.py`.