Skip to content

Permanent-tier nref allocation via switchable graphdb_nref facade#29

Merged
david-w-t merged 17 commits into
davidwt-com:mainfrom
david-w-t:develop
May 30, 2026
Merged

Permanent-tier nref allocation via switchable graphdb_nref facade#29
david-w-t merged 17 commits into
davidwt-com:mainfrom
david-w-t:develop

Conversation

@david-w-t
Copy link
Copy Markdown
Contributor

Summary

Routes all graphdb node-nref allocation through a new switchable graphdb_nref facade so that module init/1 one-time seeds land in the permanent tier [?LABEL_START, ?NREF_START) = [10001, 1000000) instead of the runtime tier (≥ 1000000). Resolves the first of two long-pending nref topics (init-seed nref tier).

Design

  • graphdb_nref (new gen_server, first child of graphdb_sup) — two phases:
    • permanent (during boot/init/1): compute-from-DB cursor over nodes keys < ?NREF_START, starting at ?LABEL_START.
    • runtime (after boot): delegates to nref_server:get_nref/0.
  • Phase held in persistent_term ({graphdb_nref, phase}), restart-safe under one_for_one.
  • graphdb:start/2 brackets boot: set_permanent_phase/0 before graphdb_sup:start_link/0, set_runtime_phase/0 after (which raises the runtime floor to ?NREF_START).
  • Spillover: if a permanent allocation reaches ?NREF_START, the facade calls nref_server:set_floor(N+1) (monotonic) so the runtime tier never collides.
  • Tier boundaries are now macros ?LABEL_START / ?NREF_START in graphdb_nrefs.hrl; the old bootstrap.terms directives and the loader set_floor call are removed. The bootstrap loader keeps its own local symbol-table counter.

All graphdb workers (graphdb_attr, graphdb_class, graphdb_instance, graphdb_language) now allocate via graphdb_nref:get_next/0.

Testing

378 green (277 CT + 101 EUnit). New graphdb_nref_SUITE covers compute-from-empty/populated, sequential uniqueness/monotonicity, spillover floor-raise, runtime delegation, and restart safety.

Docs

Spec: docs/designs/permanent-tier-nref-allocator-design.md (Status: Implemented).
Plan: docs/superpowers/plans/2026-05-28-permanent-tier-nref-facade.md.
ARCHITECTURE.md, CLAUDE.md, and apps/graphdb/CLAUDE.md updated for the facade, permanent-tier seeds, and macro-sourced boundaries.

🤖 Generated with Claude Code

david-w-t and others added 17 commits May 28, 2026 21:14
Bundles several in-progress streams that were uncommitted in the working
tree:

- Permanent-tier nref groundwork (label_start): bootstrap.terms gains a
  {label_start, 10001} directive, nref_start bumped 100000 -> 1000000;
  graphdb_bootstrap builds the label symbol table from a local counter
  before set_floor(nref_start); classify_terms/validate_label_start +
  tests and ARCHITECTURE/CLAUDE updated (390 tests green as of last
  session).
- F4 graphdb_rules design refinements (docs/designs/f4-graphdb-rules-design.md).
- New design spec: permanent-tier nref allocator via compute-from-DB,
  which supersedes the label_start directives with graphdb_nrefs.hrl
  macros during implementation
  (docs/designs/permanent-tier-nref-allocator-design.md).
- docs/diagrams/ontology-tree.md -- environment ontology visual reference.
- docs/resiliency-notes.md -- nref-stability threads to revisit.

Note: per the new allocator spec (D2), the bootstrap.terms directives
committed here will be reversed in favour of header macros when that
spec is implemented.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Revise the permanent-tier nref design from a threaded permanent-only
allocator to a single switchable graphdb_nref facade, per the recalled
least-impact/most-reuse approach:

- One entry point (graphdb_nref:get_next/0) for all graphdb node-nref
  allocation; every create function changes by one token, no
  seed-vs-runtime branching (D8).
- Phase decides the tier: permanent during init (compute-from-DB),
  runtime after the flip (delegates to nref_server). Flip lives in
  graphdb:start/2, bracketing the boot (D9).
- Bootstrap loader keeps its local counter; coexists safely since the
  facade computes-from-DB past the loader's labels (D10).
- Phase held in persistent_term, not volatile state, so a single
  facade restart at runtime cannot resurrect permanent mode and write
  permanent-tier nrefs as runtime nodes (D11 -- closes a corruption
  hole in the scan invariant).

Verified: graphdb is a peer app (start/2 invoked); all permanent
seeding is synchronous in init/1 (temporal invariant). Survives from
the prior draft: compute-from-DB core, scan invariant + forward
constraint, lazy-compute timing, spillover, header macros (D2), D6/D7.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bite-sized task-by-task plan for the graphdb_nref switchable allocation
facade per docs/designs/permanent-tier-nref-allocator-design.md: new
facade module + CT suite, supervision wiring, graphdb:start/2 phase
flip, uniform get_nref->get_next swaps across the worker modules,
bootstrap revert to macro-sourced tier boundaries, and the full test/doc
fallout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…DB, persistent_term phase)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nesses

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r); flip tier assertions

Three live nref_server:get_nref() calls in do_create_attribute/3 and
do_create_relationship_attribute_pair/3 replaced with graphdb_nref:get_next()
so all attribute seeds land in the permanent tier [?NREF_ENGLISH, ?NREF_START).
Test assertions updated from ">= 1000000" (runtime) to the permanent-tier
range check; TDD verified: tests failed before the swap and pass after.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…assertions

Swap all three nref_server:get_nref() calls in graphdb_language.erl to
graphdb_nref:get_next() so that Language Literals sub-group, base_language,
and project_language seeds land in the permanent tier during init/1.
Update graphdb_language_SUITE assertions to expect permanent-tier nrefs
(> NREF_ENGLISH and < NREF_START) and replace bare 1000000 literals with
?NREF_START throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s + loader set_floor

Tier boundaries (?LABEL_START, ?NREF_START) are now compile-time macros in
graphdb_nrefs.hrl rather than {nref_start,_}/{label_start,_} directives in
bootstrap.terms.  classify_terms/1 now returns a 2-tuple {Nodes, Rels};
do_load/0 passes the macros directly to validate/2 and build_symbol_table/4
and no longer calls nref_server:set_floor/1 (that is handled by
graphdb:start/2 via graphdb_nref:set_runtime_phase/0).  validate_label_start/2
removed.  Tests updated accordingly: 61 EUnit + 19 CT pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… stale start/2 claim

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e erase in bootstrap suite)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor Author

@david-w-t david-w-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good

@david-w-t david-w-t merged commit 8852c54 into davidwt-com:main May 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant