SP1: project/environment reference & namespace model#52
Conversation
Sub-project 1 of the project/environment separation program. Establishes,
at the API/code layer only (no record changes), that every nref reference
has a derived namespace ({environment | current-project}), cross-project
links indirect through local proxy nodes (AVP payload, no new kind), a
project-session opened against a nref-5 registry node, and the env-op vs
project-op API split that relocates relationship mutation off "instance".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
8 tasks in two PR-sized milestones — A: mechanisms (graphdb_ns pure resolution, project registry, open_session, Remote Reference proxy contract); B: required-session threading through the project op surface + relationship-mutation relocation per the env/project split. Behavior- preserving against today's single store. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
Adds graphdb_project (plain module, not gen_server) with: - register_project/1: creates a kind=instance node under Projects (nref 5) via category composition arcs (ARC_CAT_CHILD/ARC_CAT_PARENT), atomically through graphdb_mgr:transaction/1; allocates nref + rel-id pair outside the transaction fun (load-bearing deadlock invariant). - is_project/1: returns true iff the node's parents cache includes NREF_PROJECTS (5). Adds graphdb_project_SUITE with 2 CT cases (503 total, +2). TDD: RED (undef) then GREEN (both pass). Cache-invariant teardown verified: ARC_CAT_PARENT (21) is in PARENT_ARCS, kind=composition — verify_caches reconciles correctly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
Seed a "Remote Reference" class (under Classes, nref 3) and two literal attributes (`remote_project`, `remote_nref`) via idempotent init/1 seeding in graphdb_instance and graphdb_attr respectively. Add proxy recognizers: `is_proxy/1` (class-membership check) and `proxy_coordinates/1` (AVP extraction). Ship two CT cases verifying the recognizer accepts a well-formed proxy node and rejects a plain instance. Update ontology-tree.md and bump the attr-count assertion in graphdb_attr_SUITE to account for the two new literal seeds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
Thread a required project Session (first arg) through the relationship-
mutation API: graphdb_instance add_relationship/5,6,7, add_class_membership/3,
remove_relationship/4,5, update_relationship/5,6, update_relationship_both/5,6
each gate on graphdb_project:require_session/1 (via with_session/2) before any
store access; a missing/invalid session returns {error, invalid_session}.
Tier-1 *_in_txn primitives are untouched (graphdb_rules composes those and is
unaffected). graphdb_project re-exports the surface as the canonical project
API home (env/project split); graphdb_mgr:add_relationship gains the session.
Behaviour-preserving against the single store (session validated but inert).
Suites thread a memoised real session (sess() helper, pre-warmed in
init_per_testcase so its arcs are in the baseline before delta captures).
New gate tests cover both mechanisms (tier-2 plain + gen_server wrapper).
Also removed two latent warnings on this branch (dead groups/0 and unused
#relationship record in graphdb_project_SUITE).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
Thread a required project Session (first arg) through create_instance/4,5,6 (graphdb_instance) and graphdb_mgr:create_instance/4, gating on graphdb_project:require_session/1 before any store access. The rule-firing engine mints children inside create_instance's own transaction via tier-1 primitives (graphdb_rules never calls create_instance), so no further propagation is needed. Behaviour-preserving against the single store. All create_instance test call sites (186) thread the memoised sess() helper; new create_instance_rejects_bad_session gate test added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
Document SP1 across Architecture.md §6, apps/graphdb/CLAUDE.md, root CLAUDE.md, and TASKS.md (Multi-project sessions): the graphdb_ns namespace map, the graphdb_project registry + required project session, the env/project write-op split, the Remote Reference proxy contract, and the four-sub-project program (SP1 done; SP2 physical store, SP3 distribution, SP4 migration). Records the Task 7 scope refinement: mutate/1 and the instance reads (get_instance/children/compositional_ancestors/resolve_value) stay namespace-agnostic in SP1 (mutate is mixed env/project; reads are query-engine-coupled), deferred to SP2 — only the unambiguous project write ops are session-gated. Also notes the SP2 follow-up for proxy_coordinates/1 missing-AVP safety. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
Add bad-session gate tests for the update-* and add_class_membership families (every gated project-write family now has a bad-session assertion). Document two deliberate SP1 choices in the design spec: graphdb_ns is intentionally unused by production code in SP1 (it is the pure classifier the SP2 store-router will consume, not dead code), and require_session/1 is shape-only (registry existence is validated once by open_session/1; per-op re-checking is deferred to SP2 when the session binds to physical storage). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
|
Is there anything preventing (or making it difficult) to have more than one project open in a session? |
The session is bound to one project in SP1 but nothing forecloses several: the session value is fully encapsulated (only graphdb_project constructs/reads it; write ops gate via require_session/1 and assume no single-project-ness), so widening the shape is localized. The remaining work is semantic (write targeting; cross-project rule/overlay priority) and lands with SP2; resolving existing data is unaffected because no structural reference crosses a project boundary (proxy indirection). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWukKCbrN8GybaScJGU2kF
|
Nothing prevents it, and little makes it hard — the hard part is semantics, and that lands with SP2, not here. Why it's not blocked. The session is a deliberately opaque value: only Where the real work is (SP2+):
"Multiple open" is a working-set/targeting convenience for a principal with access to each; it doesn't dissolve the isolation boundary. Recommendation: keep it singleton in SP1 (behavior-preserving/YAGNI) — it's forward-compatible, and multi-project naturally lands with SP2 when writes actually route. I've added a "multi-project-session forward compatibility" note to the design doc's deferred section (commit 2cc6b75). |
Sub-project 1 of the project/environment separation program
(design:
docs/designs/project-env-reference-namespace-model-design.md).Establishes, at the API/code layer only — no
node/relationshiprecordchanges, that every nref reference has a derived namespace and that project
operations require a session. Behaviour-preserving against today's single
Mnesia store; SP2 gives the seam physical teeth.
What landed
Milestone A — mechanisms (subagent-implemented + independently reviewed)
graphdb_ns— pure namespace map (namespace_of/1,target_namespace/1→environment | project | home); exhaustive table-driven tests. Intentionally unused by production code in SP1 (the classifier the SP2 store-router will consume).graphdb_project— project registry (register_project/1,is_project/1) creating the nref-5 anchor; project session (open_session/1,session_project/1,require_session/1).remote_project/remote_nrefliteral attributes +graphdb_instance:is_proxy/1/proxy_coordinates/1. Cross-project links are local proxy nodes carrying remote coordinates as AVP payload; no structural reference crosses a project boundary. Representation only (creation/dereference are SP2/SP3). Ontology-tree diagram updated.Milestone B — required-session threading & relocation
Sessionfirst arg and reject a missing/invalid one with{error, invalid_session}:create_instance/4,5,6,add_relationship/5,6,7,remove_relationship/4,5,update_relationship/5,6(+_both),add_class_membership/3;graphdb_mgr:create_instance/4+add_relationship/5gain the session too.graphdb_project(env/project split). Tier-1*_in_txnprimitives untouched →graphdb_rulesfiring unaffected.mutate/1and the instance reads (get_instance/children/compositional_ancestors/resolve_value) stay namespace-agnostic in SP1 (likeget_node/get_relationships):mutate/1is a mixed env/project batch, and the reads are consumed bygraphdb_query(gating them would force the deferred query-session unification). Their routing lands in SP2.Testing
Full suite green: 510 CT + 141 EUnit = 651, 0 failures, 0 warnings. New bad-session gate tests cover every gated project-write family; also cleared two latent warnings on the branch.
Deferred (tracked in
TASKS.md→ Multi-project sessions)SP2 physical per-project store + allocator-from-1; SP3 distribution/residency + proxy dereference; SP4 migration. Also:
proxy_coordinates/1missing-AVP safety (harmless until SP2 proxy creation); session unification withgraphdb_query; private environment overlays.🤖 Generated with Claude Code