- Create decisions/ directory with 32 numbered ADRs (ADR-001 through ADR-032) extracted from inline DD/SD/ED/SE decision sections - Create open-questions.md with 16 OQs organized by theme, cross-referenced to ADRs, with status tracking (resolved/open) - Create README.md as architecture index with doc table, ADR table, and lifecycle status definitions (draft/reviewed/stable/deprecated) - Replace inline decision sections in all spec docs with ADR reference tables - Replace inline open questions with OQ references to centralized tracker - Update frontmatter: metagraph-module.md, overview.md, sqlite-host.md → reviewed; schema-evolution.md and encrypted-data.md remain draft - DD1-DD10 → ADR-009 through ADR-018 - D1-D8 → ADR-001 through ADR-008 - SD1-SD5 → ADR-019 through ADR-023 (SD5 folded into ADR-006/008) - ED1-ED5 → ADR-023 through ADR-027 - SE1-SE5 → ADR-028 through ADR-032
8.0 KiB
8.0 KiB
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-05-29 |
Open Questions Tracker
Cross-cutting compilation of all unresolved questions across the storage architecture documents, organized by theme. Questions that appear in multiple documents are unified here with cross-references.
When a question is resolved, update its status to resolved and add a resolution note. Once all questions in a theme are resolved, the theme section can be removed and the resolution noted in the relevant ADR.
How to Use This Document
- Each question has an ID (e.g., OQ-01), status, origin (which doc(s)), and priority
- Cross-references link related questions and ADRs
- Resolved questions have a resolution note
ADR Impact
| ADR | Resolves |
|---|---|
| ADR-003 | OQ-01 (partial — storage can start without flowgraph Module) |
| ADR-015 | OQ-05 (constraint semantics) |
| ADR-020 | OQ-02 (no nodeTypeId for now, can add later) |
Theme 1: Package Boundaries and Dependencies
OQ-01: Should @alkdev/flowgraph export a Type.Module, or should storage define its own entries with documented correspondence?
- Origin: metagraph-module.md
- Status: partially resolved
- Priority: high
- Notes: Storage can start with standalone schemas and
Type.Composite([BaseNode, CallNodeAttrs])— no dependency on flowgraph. AdoptImport()when flowgraph provides a Module. This avoids a circular dependency:@alkdev/storagedoes NOT depend on@alkdev/flowgraph. - Cross-references: ADR-003, ADR-010
OQ-02: Should concrete graph type Modules live in storage or in their respective packages?
- Origin: metagraph-module.md
- Status: resolved
- Priority: medium
- Resolution: Both. Storage provides reference Modules in
modules/that consumers can use directly or replace. Flowgraph may also export a Module — the two are compatible via Module$defs. - Cross-references: ADR-003
Theme 2: Data Model
OQ-03: Should actors be a node type or a standalone table?
- Origin: overview.md
- Status: open
- Priority: medium
- Notes: Currently
actorsis a standalone table with no relations. If identity/authentication is a graph (ACL nodes based on@alkdev/operations'Identityinterface), actors become node types. If identity needs special query patterns (auth lookups, session joins), standalone tables may be better. Decision deferred until ACL design. - Cross-references: ADR-024, encrypted-data.md
OQ-04: Should the repository layer be host-specific or host-agnostic?
- Origin: overview.md
- Status: open
- Priority: medium
- Notes: A host-agnostic repository requires an abstraction over Drizzle's query builder. A host-specific repository is simpler but means duplicating query logic for PG. Decision: start host-specific in SQLite, extract common patterns later.
- Cross-references: sqlite-host.md
OQ-05: Should *EdgeConstraints entries use Type.Ref or Type.String for allowed source/target types?
- Origin: metagraph-module.md
- Status: resolved
- Priority: low
- Resolution:
Type.String()— the constraint arrays contain node type names, not node type schemas. - Cross-references: ADR-015
OQ-06: How does the graph pointer abstraction interact with the repository layer?
- Origin: metagraph-module.md
- Status: resolved
- Priority: low
- Resolution: For v1, repository functions use direct key-based addressing. Validate on read — if data doesn't match the Module entry, throw. Typed pointers are post-v1 (ADR-017).
- Cross-references: ADR-017, forward-look.md
Theme 3: Encryption and Security
OQ-07: Should we add encryptRaw() for performance?
- Origin: encrypted-data.md
- Status: open
- Priority: low
- Notes: PBKDF2 derivation adds ~100ms per operation. For batch operations (e.g., rotating 1000 keys), this adds up. An
encryptRaw()that skips PBKDF2 would be much faster. Decision: add in a future iteration if performance demands it.
OQ-08: Should the key attribute on secret nodes be encrypted?
- Origin: encrypted-data.md
- Status: resolved
- Priority: low
- Resolution: Plaintext key names are acceptable for now. If secret names are sensitive, add a
keyHashattribute for blind lookups.
OQ-09: Should secret nodes have lastUsedAt and expiresAt as first-class columns?
- Origin: encrypted-data.md
- Status: resolved
- Priority: low
- Resolution: For spoke use (occasional lookups), JSON attributes are fine. For hub use (high-throughput key validation), a standalone
api_keystable with proper indexes is still needed.
Theme 4: Schema Evolution
OQ-10: Can Value.Diff Edit[] be reliably classified as breaking vs non-breaking?
- Origin: schema-evolution.md
- Status: open
- Priority: high
- Notes: The classification table in schema-evolution.md is theoretical. A POC should validate whether
Edit[]output contains enough information to distinguishString → Literal("x")(narrowing, non-breaking) fromString → Number(incompatible, breaking). Alternative: skip classification and just useValue.Check(newSchema, storedData)for verification.
OQ-11: Should the repository layer auto-migrate data on schema change, or require explicit consumer action?
- Origin: schema-evolution.md
- Status: open
- Priority: high
- Notes: Conditional on OQ-10 POC outcome. If classification is feasible, the repository layer auto-applies
Value.Castfor non-breaking changes and requires explicit consumer action for breaking changes. If classification is not feasible, the repository layer auto-appliesValue.Castonly whenValue.Check(newSchema, storedData)passes for all stored data.
OQ-12: How does schema evolution interact with the hub's event-sourced call graph?
- Origin: schema-evolution.md
- Status: open
- Priority: medium
- Notes: If the hub migrates to event-sourced replay (projector evolution), storage's call graph tables become disposable projections. But other graph types (ACL, tasks, secrets) may not have an event stream to replay from. The schema evolution design should work for both projections and direct-persisted data.
OQ-13: Should schema evolution events be part of the event stream?
- Origin: schema-evolution.md
- Status: open
- Priority: low
- Notes: Post-v1. For v1, schema changes are applied directly via the repository layer with version tracking.
Theme 5: Encrypted Data Scope
OQ-14: Should encryption be per-attribute, per-node, or per-graph?
- Origin: overview.md
- Status: resolved
- Priority: high
- Resolution: Per-attribute. The
EncryptedDataschema is a single attribute within a node type, not the entire node. This preserves queryability on non-sensitive fields (ADR-023).
OQ-15: Should key management be in this package?
- Origin: overview.md
- Status: resolved
- Priority: high
- Resolution: No.
@alkdev/storageprovides encryption/decryption primitives but NOT key management. The consuming application provides the key ring (ADR-026).
Theme 6: Repository Layer
OQ-16: Should the repository layer live in @alkdev/storage or in a consumer package?
- Origin: overview.md
- Status: resolved
- Priority: high
- Resolution: The repository CRUD layer (host-specific typed queries, schema validation before writes) belongs in
@alkdev/storage. The operations bridging layer (generatingOperationSpecs from metagraph schemas) belongs in a consumer or adapter package. These are separate concerns — CRUD is a storage concern; call protocol integration is an application concern.