# RAC v0.7.11 — Hybrid Metadata and System-Assigned Identity

## Status

Planned

## Context

RAC currently derives artifact identity and classification from Markdown content,
artifact-specific sections, filenames, and repository conventions.

This supports human-readable artifacts, but creates ambiguity for repository-scale
capabilities.

Identity may currently depend on:

- Filename prefixes
- Explicit ID sections
- Artifact-specific fields
- Classification results

Repository intelligence requires a more stable contract.

Artifacts must retain identity when they are:

- Renamed
- Moved
- Reclassified
- Referenced by other artifacts

RAC also requires an explicit location for machine-operational metadata without moving
human product knowledge out of Markdown.

The accepted architectural direction is:

- YAML frontmatter for machine-operational metadata
- Markdown sections for human reasoning and product meaning
- Opaque, system-assigned IDs for canonical artifact identity
- Repository-local identity namespaces established by `rac init`

## Requirement

RAC shall introduce a hybrid metadata envelope and system-assigned artifact identity.

Newly generated artifacts shall be capable of carrying canonical metadata such as:

```yaml
---
schema_version: 1
id: RAC-01JY4M8X
type: decision
---
```

The Markdown body shall continue to contain artifact content:

```markdown
# Markdown Is the Canonical Source Format

## Status

Accepted

## Context

RAC requires a canonical source format.
```

## Goals

- Establish one canonical location for machine-operational metadata.
- Introduce stable artifact IDs independent of type, path, and filename.
- Support offline and concurrent artifact creation.
- Preserve Markdown as the canonical form of product knowledge.
- Maintain compatibility with existing artifacts during migration.
- Create the metadata foundation for relationships, Explorer, Watchkeeper, and IDE
  integrations.

## Initiatives

### Initiative 1 — Repository Identity Configuration

Introduce:

```bash
rac init
```

to establish a repository identity namespace. (No `rac init` command exists
today; this release introduces it.)

Representative repository configuration:

```yaml
repository_key: RAC
```

The repository key shall:

- Be deterministic within the repository
- Be used as the recognizable prefix for generated artifact IDs
- Remain independent of directory layout
- Be validated for supported characters and length

The implementation shall define behavior when:

- RAC is initialized in an existing repository
- A repository key already exists
- A requested key conflicts with existing artifact IDs
- Configuration is missing or malformed

Changing an established repository key shall not silently rewrite existing IDs.

### Initiative 2 — Frontmatter Parser

Add support for leading YAML frontmatter.

The parser shall:

- Detect a leading frontmatter block
- Parse supported metadata fields
- Reject malformed YAML
- Reject duplicate keys
- Validate field types
- Preserve artifacts without frontmatter
- Avoid unsafe YAML construction
- Produce actionable errors

Initial supported fields:

```yaml
schema_version: 1
id: RAC-01JY4M8X
type: decision
relationships: {}
```

The implementation may stage relationship migration separately, but the metadata model
must reserve and define the canonical location.

### Initiative 3 — Canonical Metadata Model

Introduce a normalized metadata abstraction in RAC Core.

Consumers should access:

```python
artifact.metadata.id
artifact.metadata.type
artifact.metadata.schema_version
artifact.metadata.relationships
```

They should not need to know whether an artifact was parsed from:

- New frontmatter
- A legacy ID section
- Filename-derived identity
- Existing relationship sections

During migration, RAC Core may expose normalized values from legacy sources.

The normalized model shall also expose metadata provenance where required for conflict
detection and migration.

### Initiative 4 — Opaque ID Generation

Introduce a branch-safe, offline-capable ID generator.

Generated IDs shall:

- Use the repository key as a prefix
- Use an opaque collision-resistant suffix
- Avoid shared sequential allocation state
- Remain stable once written
- Be unique within the repository namespace

Representative output:

```text
RAC-01JY4M8X
```

The implementation contract shall specify:

- Character set
- Case normalization
- Suffix length
- Collision handling
- Test strategy
- Whether time-sortability is required

### Initiative 5 — Artifact Creation Integration

Integrate identity assignment into artifact generation.

Representative workflow:

```bash
rac new decision
```

Generated artifact:

```yaml
---
schema_version: 1
id: RAC-01JY4M8X
type: decision
---
```

The command shall:

- Read the repository key
- Generate one new ID
- Write canonical frontmatter
- Use stable frontmatter key ordering
- Avoid overwriting existing files
- Produce deterministic artifact structure apart from the intentionally unique ID

Users shall not need to manually assign IDs for newly generated artifacts.

### Initiative 6 — Identity Validation

Extend repository validation to detect:

- Missing required IDs for new-format artifacts
- Duplicate IDs
- Invalid repository prefixes
- Invalid ID syntax
- Conflicting frontmatter and legacy identity
- Unsupported schema versions

Duplicate identity shall be treated as a repository error.

The same ID shall not identify multiple artifacts, even when those files are in
different directories or have different types.

### Initiative 7 — Legacy Compatibility

Continue supporting artifacts without frontmatter during the migration period.

Legacy identity may continue to be derived from:

- Explicit ID sections
- Artifact-specific identifier fields
- Filename conventions

When both canonical frontmatter identity and legacy identity are present:

- Matching values may be accepted during migration.
- Conflicting values shall produce an error.
- RAC shall not silently select one identity.

No backwards-compatibility shim shall preserve obsolete module ownership after internal
refactors. Internal code shall consume the canonical metadata and identity APIs directly.

### Initiative 8 — Metadata Migration Support

Provide at least a documented migration path for existing artifacts.

A future or included command may support:

```bash
rac migrate metadata rac/
```

or:

```bash
rac improve artifact.md
```

Migration behavior shall:

- Preserve Markdown content
- Add canonical frontmatter
- Preserve existing identity where safe
- Generate a new opaque ID where no canonical identity exists
- Report conflicts rather than guessing
- Avoid rewriting unrelated formatting

Whether automated migration ships in v0.7.10 shall be confirmed in the implementation
contract.

## Implementation Contract

The following decisions are pinned for v0.7.11.

### Repository Configuration

- `rac init [directory] [--key KEY]` writes `.rac/config.yaml` containing
  `repository_key: KEY` in the target directory (default: current directory).
- The key defaults to `RAC` when `--key` is omitted.
- Key syntax: `^[A-Z][A-Z0-9]{1,9}$` (2–10 characters, uppercase alphanumeric,
  leading letter).
- Re-running `rac init` with the same key is idempotent success (exit `0`);
  a different key is an error (exit `1`) — RAC never silently rewrites an
  established namespace.
- Configuration discovery walks upward from the artifact's directory toward the
  filesystem root, using the first `.rac/config.yaml` found.

### YAML Parsing

- PyYAML (`pyyaml>=6`) becomes a core dependency.
- Frontmatter is parsed with a strict SafeLoader subclass that rejects
  duplicate keys (plain `safe_load` accepts them silently, which ADR-025
  forbids) and never constructs arbitrary objects.

### ID Generation

- Format: `<REPOSITORY_KEY>-<SUFFIX>`, suffix is 12 characters of Crockford
  base32 (uppercase, no I/L/O/U): an 8-character millisecond-timestamp segment
  (time-sortable, ULID-style) followed by a 4-character CSPRNG segment.
- IDs are matched case-insensitively and normalized to uppercase.
- Collision handling: `rac new` checks the generated ID against the repository
  index and regenerates (bounded retries); post-merge duplicates are caught by
  identity validation.
- The generator accepts injectable clock and entropy for deterministic tests.

### Creation Integration

- `rac new` without an established repository key fails with exit `2` and an
  actionable message pointing at `rac init`. No fallback, no implicit init.
- Generated frontmatter uses stable key order: `schema_version`, `id`, `type`.
  No `relationships` key is emitted until relationships migrate.

### Migration

- Automated migration tooling (`rac migrate metadata`) is deferred beyond
  v0.7.11; the documented path is manual frontmatter addition, validated by
  `rac validate`.

### Testing

- Golden tests for output that would contain generated IDs inject a fixed
  generator (monkeypatch seam, like `_USE_COLOR`), keeping goldens
  byte-stable.

## Output Contracts

Repository-facing structured outputs shall expose canonical opaque IDs.

For example:

```json
{
  "id": "RAC-01JY4M8X",
  "type": "decision",
  "title": "Markdown Is the Canonical Source Format",
  "path": "rac/decisions/markdown-first.md"
}
```

Existing command contracts shall remain stable unless explicitly versioned.

Fields added to existing JSON outputs shall follow RAC's additive compatibility rules.

## Non-Goals

- Moving status into frontmatter
- Moving context, rationale, or acceptance criteria into frontmatter
- Centralized cloud ID allocation
- Jira-style workflow management
- Assignees, sprints, backlogs, or due dates
- Making frontmatter mandatory for all legacy artifacts immediately
- Automatically deriving dates from Git or filesystem timestamps
- Making Explorer responsible for identity generation

## Success Measures

- `rac init` establishes a valid repository key.
- `rac new` assigns an opaque ID without user intervention.
- Concurrently generated IDs do not collide in normal Git workflows.
- IDs remain unchanged after files are moved or renamed.
- Artifact type can change without changing identity.
- Duplicate IDs are detected deterministically.
- Existing artifacts remain readable and supported during migration.
- Product reasoning remains in Markdown sections.
- Repository services consume a single canonical identity API.

## Related Decisions

- ADR-025 Hybrid Artifact Metadata
- ADR-026 Opaque System-Assigned Artifact Identity
- ADR-015 Explorer as a Consumer

## Dependencies

- Repository Index
- Artifact templates and `rac new`
- Canonical artifact classification
- Core identity services

## Follow-On Work

v0.7.12 shall introduce human-friendly artifact lookup and resolution over the opaque
identity model.