# v0.5 Enterprise Document Processing Ontology — Design Memo

> **Status**: **LOCKED** (2026-06-12, pre-implementation). This memo
> defines the design contract for the v0.5 Stream B.5 work: extending
> JAMES's existing entity-type registry with **generic enterprise
> document subtypes** + lifecycle states + relations + roles. The
> design honours CLAUDE.md rule #1 (no vertical-domain features until
> v1.0) by scoping every type / relation / role to mother-platform
> horizontality — any enterprise, any vertical.
>
> **Authors**: Jiwon Seo
> **Date**: 2026-06-12
> **Cycle**: v0.5 entry (`docs/handovers/v0.5-entry-2026-06-12.md`)
> **Predecessors**:
> - `core/ontology.py` α-8 horizontal-types extension (2026-06-02, PRs
>   #688 + #689); the α-8 comment explicitly declares "v0.5 domain
>   packs extend this dict via plugin mechanism (forward compat hook
>   per design memo §3.4)" — this memo IS that v0.5 follow-up.
> - `docs/PLATFORM_READINESS.md` §3 Dim F (the production-proof gate
>   B.5 prepares for)
> - `docs/strategy/v0.5-pre-loi-materials/02-technical-brief.md`
>   (customer-facing description of audit + temporal axes B.5 builds on)
>
> **Scope discipline**: Every type / relation / role added by this
> memo must be **defensible at any enterprise regardless of vertical**
> (legal, food, retail, finance, healthcare, manufacturing, public-
> sector, education). If a proposed addition only makes sense for one
> vertical, it is rejected from this memo and deferred to a v1.0
> vertical-pack plugin.

---

## 1. Why now

v0.5 = first-domain pilot path. The Dim F gate (≥6 months external
customer pilot + 0 core regressions) requires JAMES to handle a
customer's actual documents. The α-8 ontology gave 4+5=9 horizontal
entity types (person / org / concept / document / event / date /
location / quantity / project) but stopped at the level of "document
as a node". A customer's contracts, policies, procedures, memos, and
meeting minutes are all `document` nodes, indistinguishable to the
graph, indistinguishable to the retrieval layer.

For a customer pilot to be productive, the operator (and the customer
operator) needs to be able to say:

- "Retrieve all **policies** that were **published** between Q2 and
  Q4 2025, **approved by** the legal officer, that **reference**
  contract co-CON-001."

Today this query is approximate (the graph engine can answer the
relation walk; the lifecycle layer can answer time-validity; but the
type-filter for "policy" specifically vs "any document" is missing).

B.5 closes that gap **at the mother-platform level** — any enterprise
has the same 10 document subtypes, the same 7 lifecycle states, the
same 4 roles. Vertical specialisation (NDA / governing-law / force-
majeure / drug_interaction / inventory_record / etc.) waits for v1.0
plugin packs.

## 2. Scope (in / out)

### 2.1 In scope (mother-level additions)

| Layer | What | Source of truth (after B.5.b) |
|---|---|---|
| **Entity subtypes** of `document` | 10 generic enterprise document classes (see §3.1) | `core/ontology.py::DOCUMENT_SUBTYPES` |
| **Lifecycle states** | 7 generic enterprise document lifecycle states (see §3.2) | `core/lifecycle/document_lifecycle.py` (new module) |
| **Document-specific relations** | 5 new relation types layered on existing graph (see §3.3) | `core/ontology.py::RELATION_TYPES` (extended) |
| **Enterprise roles** for documents | 4 generic role tokens layered on existing RBAC (see §3.4) | `core/ontology.py::ENTERPRISE_ROLES` |
| Plugin extension point for v1.0 vertical packs | Documented hook | This memo §6 |

### 2.2 Out of scope (blocked for v1.0 or LOI gate)

- **Legal-specific document subtypes** (NDA, indemnification, force_majeure, governing_law, term_sheet, BAA, MSA, etc.) — vertical
- **Medical-specific** (drug interaction, treatment protocol, consent form) — vertical
- **Finance-specific** (10-K, audit-rule-X, position-sheet, MiFID disclosure) — vertical
- **Customer-specific workflow / approval chain** — addenda after LOI
- **Multi-tenant tenant-isolation** beyond existing `JAMES_WORKSPACE` — separate Stream B.2 review
- **Plugin API freeze** (the v1.0 gate) — separate cycle B.3 review

### 2.3 Why each in-scope item is mother-level

For each in-scope addition, this memo justifies horizontality by
demonstrating applicability across **at least 4 distinct verticals**.
If a proposed addition fails the 4-vertical test, it does not enter
this memo.

(See §3 for the per-addition justification.)

## 3. The four additions

### 3.1 Document subtypes — 10 generic enterprise classes

Subtypes are added to the **existing** `core/ontology.py::ENTITY_TYPES["document"]`
entry as a child registry. They are NOT new top-level entity types
(would inflate the entity-type vocabulary unnecessarily).

```python
# core/ontology.py (B.5.b code)
DOCUMENT_SUBTYPES: Dict[str, Dict] = {
    "contract":           {"parent": "document", "since": "v0.5"},
    "policy":             {"parent": "document", "since": "v0.5"},
    "procedure":          {"parent": "document", "since": "v0.5"},
    "memo":               {"parent": "document", "since": "v0.5"},
    "report":             {"parent": "document", "since": "v0.5"},
    "specification":      {"parent": "document", "since": "v0.5"},
    "meeting_minutes":    {"parent": "document", "since": "v0.5"},
    "standard":           {"parent": "document", "since": "v0.5"},
    "form":               {"parent": "document", "since": "v0.5"},
    "record":             {"parent": "document", "since": "v0.5"},
}
```

#### Horizontality justification (4-vertical test for each)

| Subtype | Definition (1 line) | Legal | Food | Retail | Finance |
|---|---|---|---|---|---|
| `contract` | Binding agreement between two or more parties | Vendor contract / NDA | Supply contract / franchise | Vendor / customer / lease | Loan / counterparty / ISDA |
| `policy` | Internal rule the org has bound itself to follow | Code of conduct, conflict-of-interest | Food safety policy, HACCP rules | Refund policy, anti-money-laundering | Risk policy, AML, FATCA |
| `procedure` | Step-by-step operational instructions | Disclosure procedure | Recall procedure | Returns procedure | Trade settlement procedure |
| `memo` | Internal communication (non-binding) | Practice-area memo | Operations memo | Store-manager memo | Trading desk memo |
| `report` | Analytical output produced from data | Litigation status | Quality audit report | Sales report | 10-K, internal audit |
| `specification` | Technical requirements / design contract | Contract specification | Recipe / formulation | Product spec | Trading-system spec |
| `meeting_minutes` | Formal record of a meeting | Board minutes | Quality committee | Mgmt committee | Risk committee |
| `standard` | Reference standard (internal or external) | Bar association standard | FDA / ISO 22000 | Industry standard | Basel III ref |
| `form` | Structured input document | Engagement letter | Inspection form | Customer form | KYC form |
| `record` | Transaction log / event audit record | Conflict-check log | Production log | POS / inventory record | Trade ticket / journal |

All 10 subtypes pass the 4-vertical test → mother-level admissible.

#### What does NOT enter this list (4-vertical failure examples)

- `non_disclosure_agreement` → legal-only sub-pattern of `contract` → vertical
- `recipe` → food-only sub-pattern of `specification` → vertical
- `10_K_report` → finance-only sub-pattern of `report` → vertical
- `treatment_protocol` → medical-only sub-pattern of `procedure` → vertical

These belong in v1.0 vertical packs.

### 3.2 Lifecycle states — 7 generic document states

A document moves through a state machine. JAMES already provides T1
(temporal validity intervals) and T7 (supersede chains). B.5 layers
a **named state token** on top so the user can say *"published"* or
*"superseded"* instead of *"valid_to=null and supersede_by=null"*.

| State | Definition | T1+T7 equivalent | Re-enterable? |
|---|---|---|---|
| `DRAFT` | Being written; no validity guarantee | `valid_from=null` | yes (returns to DRAFT after revision) |
| `IN_REVIEW` | Submitted for review, not yet approved | `valid_from=null, in_review=true` | no (moves forward only) |
| `APPROVED` | Reviewed and signed off; not yet published / effective | `valid_from=null, approved_at=<ts>` | no |
| `PUBLISHED` | Currently in force (the actively-used version) | `valid_from=<ts>, valid_to=null, supersede_by=null` | no |
| `SUPERSEDED` | Replaced by a newer version | `valid_to=<ts>, supersede_by=<doc_id>` | no |
| `ARCHIVED` | Kept for audit but not current; pre-publication path | `valid_to=<ts>, supersede_by=null` | no |
| `REVOKED` | Formally invalidated (rare; for emergency rescind) | `valid_to=<ts>, revoked=true` | no |

#### State machine

```
DRAFT  ←─────────────┐
  ↓                  │
IN_REVIEW ──── back──┘  (reviewer requests changes)
  ↓
APPROVED
  ↓
PUBLISHED  ←─── new version PUBLISHED ←─── this version SUPERSEDED
  ↓                                              ↓
ARCHIVED                                         ARCHIVED
  ↓
REVOKED  (emergency only; not a normal transition)
```

#### Implementation contract (B.5.b)

```python
# core/lifecycle/document_lifecycle.py (NEW module)
from enum import Enum

class DocumentLifecycleState(Enum):
    DRAFT       = "draft"
    IN_REVIEW   = "in_review"
    APPROVED    = "approved"
    PUBLISHED   = "published"
    SUPERSEDED  = "superseded"
    ARCHIVED    = "archived"
    REVOKED     = "revoked"

# 1:1 mapping to T1+T7 frontmatter — pure helper, no state machine
# enforcement at this layer (T7 supersede chain owns the transitions).
def state_from_t1_t7(valid_from, valid_to, supersede_by, approved_at, in_review, revoked) -> DocumentLifecycleState: ...
def t1_t7_from_state(state: DocumentLifecycleState) -> dict: ...
```

**No state-machine enforcer.** This module is a **pure interpretation
layer over T1+T7**. T1 + T7 own truth; this module names the truth.

### 3.3 Document-specific relations — 5 layered on existing graph

| Relation | Domain → Range | Cardinality | Semantics |
|---|---|---|---|
| `AUTHORED_BY` | document → person | many-to-many | Author of the document (creator) |
| `APPROVED_BY` | document → person | many-to-many | Approver (sign-off authority) |
| `REFERENCES` | document → document | many-to-many | A cites B (one-way reference) |
| `DERIVED_FROM` | document → document | many-to-many | A is derived/based on B (different from REFERENCES; implies content reuse / inheritance) |
| `SUPERSEDES` (existing T7) | document → document | one-to-one (in chain) | T7 chain: A supersedes B (B becomes SUPERSEDED state) |

#### Horizontality justification

AUTHORED_BY / APPROVED_BY / REFERENCES / DERIVED_FROM / SUPERSEDES are
all directly meaningful at any enterprise. No vertical specialisation.

#### Implementation

```python
# core/ontology.py (B.5.b code) — extend existing RELATION_TYPES dict
RELATION_TYPES.update({
    "AUTHORED_BY":  {"label": "작성자",  "inverse": "AUTHORED",  "transitive": False, "weight": 1.0, "sensitive": False, "allowed_head": {"document"}, "allowed_tail": {"person"}},
    "APPROVED_BY":  {"label": "승인자",  "inverse": "APPROVED",  "transitive": False, "weight": 1.0, "sensitive": True,  "allowed_head": {"document"}, "allowed_tail": {"person"}},
    "REFERENCES":   {"label": "참조함",  "inverse": "REFERENCED_BY", "transitive": False, "weight": 0.8, "sensitive": False, "allowed_head": {"document"}, "allowed_tail": {"document"}},
    "DERIVED_FROM": {"label": "유래",    "inverse": "DERIVED_INTO", "transitive": True,  "weight": 0.9, "sensitive": False, "allowed_head": {"document"}, "allowed_tail": {"document"}},
    # SUPERSEDES already exists in T7 layer; not added here
})
```

Note `APPROVED_BY.sensitive = True` (the approver's identity may be
RBAC-restricted in some enterprises — legal officer / general counsel
visibility may require manager+ role).

### 3.4 Enterprise roles — 4 generic role tokens

These augment the existing RBAC (`admin / manager / employee /
external`) with **document-relationship roles**. A user's RBAC role
controls baseline access; the document role describes their
**relationship to a specific document**.

| Role | Permissions over the related document |
|---|---|
| `AUTHOR` | read + edit (until APPROVED) |
| `REVIEWER` | read + comment + reject |
| `APPROVER` | read + approve (sign-off) |
| `READER` | read only |

#### Implementation contract

```python
# core/ontology.py (B.5.b code) — new top-level registry
ENTERPRISE_ROLES: Dict[str, Dict] = {
    "AUTHOR":   {"perms_over_doc": {"read", "edit", "submit_review"}},
    "REVIEWER": {"perms_over_doc": {"read", "comment", "reject"}},
    "APPROVER": {"perms_over_doc": {"read", "approve", "reject"}},
    "READER":   {"perms_over_doc": {"read"}},
}
```

Permission tokens (`read / edit / submit_review / comment / reject /
approve`) are **suggestive** at this layer — they document the
intended semantics. Actual enforcement lives in the existing security
pipeline (`core/security/`); B.5 is a **registry** + **semantic tokens**
contribution, NOT a permission rewrite.

## 4. What B.5.b implementation MUST NOT do

- ❌ Add any vertical subtypes (legal, food, retail, finance, etc.)
- ❌ Rewrite the existing RBAC enforcement layer
- ❌ Rewrite T1 / T7 (the lifecycle states are interpretive, not enforced here)
- ❌ Change the graph-engine relation walker
- ❌ Touch retrieval-side / reasoning-side modules (no `core/retrieval/`, no `core/reasoning/`)
- ❌ Add any LLM-judge or LLM-based classification
- ❌ Modify `core/ontology.py::ENTITY_TYPES` top-level structure (add only `DOCUMENT_SUBTYPES`)

If the implementation finds itself doing any of the above, it has
exceeded B.5 scope and must be split into a separate cycle.

## 5. Test plan (B.5.c)

### 5.1 Unit tests

| Module | Test | Coverage |
|---|---|---|
| `core/ontology.py` (extended) | `DOCUMENT_SUBTYPES` registry shape, every entry has `parent='document'` + `since` field | New registry contract |
| `core/ontology.py` (extended) | New `RELATION_TYPES` entries pass `is_valid_relation_triple()` validation | Existing validator survives |
| `core/lifecycle/document_lifecycle.py` (new) | `state_from_t1_t7` round-trips correctly for each of the 7 states | Per-state mapping |
| `core/lifecycle/document_lifecycle.py` (new) | `t1_t7_from_state` returns valid T1+T7 frontmatter dict | Per-state inverse |
| `ENTERPRISE_ROLES` registry | Shape contract; every role has `perms_over_doc` non-empty set | New registry contract |

### 5.2 Integration tests (mother-platform discipline)

- Existing `tests/test_ontology.py` / `tests/test_graph_engine.py` /
  `tests/test_t7_release_gating_invariants.py` MUST stay green
  (proves B.5 is additive only).
- B.5 adds NO new release-gating invariant tests (the existing T7
  invariants are sufficient).

### 5.3 Test fixture — generic enterprise document corpus (B.5.c)

A small fixture `tests/fixtures/v0.5_enterprise_documents.json` with
**~10 generic enterprise documents** (one per subtype) demonstrating
each subtype + each relation + each role. The corpus is **deliberately
domain-neutral** — references to a fictional company "Acme Co.",
its policies / contracts / memos / etc., applicable to any vertical
(no legal-specific clauses, no medical content, etc.).

## 6. Plugin extension point for v1.0 vertical packs

When v1.0 ships and vertical packs unlock (after the v0.5 → v0.6 →
v1.0 gate sequence in `docs/PLATFORM_READINESS.md`), vertical packs
will hook into the registries B.5 establishes:

```python
# Example vertical-pack pseudocode (v1.0+ ONLY)
from core.ontology import DOCUMENT_SUBTYPES

# A legal-pack vertical plugin extends DOCUMENT_SUBTYPES with verticals:
DOCUMENT_SUBTYPES.update({
    "non_disclosure_agreement": {"parent": "contract", "since": "v1.0-legal-pack"},
    "force_majeure_clause":     {"parent": "contract", "since": "v1.0-legal-pack"},
    "governing_law_clause":     {"parent": "contract", "since": "v1.0-legal-pack"},
})
```

The parent-pointer chain (`non_disclosure_agreement → contract →
document → Entity`) preserves the horizontal taxonomy while letting
verticals add depth. **This is what α-8's "v0.5 domain packs extend
this dict via plugin mechanism" comment anticipated.**

## 7. Honest framing / non-goals

| What B.5 claims | What B.5 does NOT claim |
|---|---|
| 10 document subtypes are sufficient for **identification of document class** at any enterprise | They are sufficient for **understanding the document content** (that's the LLM's job) |
| 7 lifecycle states are sufficient for **time-validity + supersede semantics** | They model **all enterprise workflows** (some enterprises have additional states like "approved-with-conditions" — those would be vertical packs in v1.0) |
| 5 new relations cover **the common document-document and document-person edges** | They cover all relations (e.g., `BINDS` / `IMPLEMENTS` / `OVERRIDES` would be vertical) |
| 4 enterprise roles cover **the common document-relationship roles** | They cover all roles (e.g., `CUSTODIAN` / `CO-SIGNATORY` — vertical) |

This is mother-level. The contribution is the **registry + semantic
contract**, not the comprehensive enterprise workflow model.

## 8. Implementation sequencing

| Phase | Work | Predecessor |
|---|---|---|
| **B.5.a** | This memo (design LOCK) | — |
| **B.5.b** | Code: `core/ontology.py` extension + `core/lifecycle/document_lifecycle.py` new module + `ENTERPRISE_ROLES` registry | B.5.a |
| **B.5.c** | Test fixture (`tests/fixtures/v0.5_enterprise_documents.json`) + unit tests | B.5.b |
| **B.5.d** | (Optional, after dogfooding) Integration with retrieval-side typed-filter (`core/graph_typed_filter.py` extension) | B.5.b + Stream A.3 dogfooding feedback |

B.5.b and B.5.c can ship in one PR (small; ~3-4h work). B.5.d is
gated on Stream A.3 dogfooding feedback (the user's actual use cases
inform whether typed-filter integration is the right next layer).

## 9. Acceptance criteria for B.5.b PR review

The B.5.b PR will be reviewable if and only if:

1. ✓ All 10 document subtypes appear in `DOCUMENT_SUBTYPES`
2. ✓ All 7 lifecycle states appear in `DocumentLifecycleState` enum
3. ✓ All 5 new relations appear in `RELATION_TYPES` (4 new + 1
   existing SUPERSEDES preserved)
4. ✓ All 4 enterprise roles appear in `ENTERPRISE_ROLES`
5. ✓ No vertical-specific entries anywhere
6. ✓ All existing tests pass
7. ✓ Test fixture covers each subtype, each relation, each role at
   least once
8. ✓ ruff F-class clean
9. ✓ This design memo cited in the PR description

If any criterion fails, the PR is rejected and the implementation
is revised to meet this memo's contract.

## 10. Related

- `core/ontology.py` (target of extension)
- `core/lifecycle/{schema,supersede_chain,contradiction_arbiter,
  causality}.py` (T1 + T7 layer this design builds on)
- `core/graph_typed_filter.py` (α-8 typed filter; possible B.5.d
  integration target)
- `docs/PLATFORM_READINESS.md` §3 (Dim F gate)
- `docs/handovers/v0.5-entry-2026-06-12.md` (v0.5 cycle entry)
- `docs/strategy/v0.5-pre-loi-materials/02-technical-brief.md`
  (customer-facing audit + temporal axes)
- Memory: `feedback_self_evaluation_trap.md` (rationale for keeping
  this purely horizontal — vertical-pack design would be
  self-vertical), `feedback_finding_size_honest_framing.md` (the
  "registry + semantic contract" claim, not "comprehensive workflow
  model")
