Skip to content

Node soft-retire: retire_node/unretire_node (write-path slice A)#42

Merged
david-w-t merged 9 commits into
davidwt-com:mainfrom
david-w-t:develop
Jun 18, 2026
Merged

Node soft-retire: retire_node/unretire_node (write-path slice A)#42
david-w-t merged 9 commits into
davidwt-com:mainfrom
david-w-t:develop

Conversation

@david-w-t

Copy link
Copy Markdown
Contributor

Implements node soft-retire — write-path slice A. "Deleting" a runtime
node is now a reversible soft-retire via a boolean retired marker AVP:
the node and all its arcs stay in Mnesia, so no arc or cache is ever
orphaned and no environment-vs-project discriminator is needed (the
env/project split is not physically realized — single shared nodes
table, instances on the environment runtime allocator, Projects category
an empty scaffold).

delete_node/1 is deliberately left untouched ({error, not_implemented})
and reserved for a future real (hard) delete.

What landed

  • graphdb_attr seeds a boolean retired literal-attribute (Attribute
    Literals sub-group, nref 7), exposed via seeded_nrefs/0 — mirroring L9
    instantiable.
  • graphdb_mgr retire_node/1 + unretire_node/1: idempotent; tier-1
    set_retired_/3 primitive run through the existing transaction/1 seam;
    the retired nref is fetched lazily + cached (graphdb_mgr starts before
    graphdb_attr); refuse the whole permanent tier (nref < ?NREF_START)
    with {error, permanent_node_immutable}; runtime-tier missing node →
    {error, not_found}.
  • graphdb_mgr public get_node/1 returns {error, retired} for a
    retired node; internal do_get_node/1 stays raw (workers/queries read
    Mnesia directly, so traversal/inheritance visibility is unchanged — the
    pragmatic-middle scope).
  • graphdb_instance refuses a retired node as new participation:
    {class_retired,_} (create_instance / add_class_membership target),
    {parent_retired,_} (create_instance parent), {endpoint_retired,_}
    (add_relationship endpoint).
  • Docs: Architecture, ontology-tree, TASKS (slice A → IMPLEMENTED + two
    follow-up tasks: retired-rules-must-not-fire, unify-permanent-tier-
    immutability), README counts.

Design / plan

  • docs/designs/delete-node-soft-retire-design.md
  • docs/superpowers/plans/2026-06-17-delete-node-soft-retire.md

Tests

Full suite 537 green — 432 CT + 105 EUnit, zero warnings. Built via
subagent-driven development: per-task spec+quality reviews + a whole-branch
review (Ready to merge: Yes, no Critical/Important). The three existing
delete_node guard tests stay green unchanged.

🤖 Generated with Claude Code

david-w-t and others added 9 commits June 17, 2026 11:54
Design for write-path slice A node deletion as a reversible soft-retire
rather than a hard delete. "Deleting" a runtime node stamps a boolean
`retired` lifecycle AVP; the node and its arcs stay in Mnesia, so nothing
orphans and no environment-vs-project discriminator is needed (the
env/project split is not physically realized yet — one shared nodes table,
instances on the environment runtime allocator, Projects category an empty
scaffold).

Key decisions:
- New ops retire_node/1 + unretire_node/1; delete_node/1 left untouched and
  reserved for a future real (hard) delete.
- retire/unretire refuse the whole permanent tier (nref < ?NREF_START) with
  a new permanent_node_immutable atom; delete_node + category guard and its
  tests are unchanged.
- get_node/1 returns {error, retired}; internal do_get_node stays raw.
- Pragmatic-middle visibility: hide from direct lookup + block new
  participation (retired class target/parent/arc endpoint); existing
  structural participation deferred.

TASKS.md: mark slice A designed; add follow-ups — retired rules must not
fire, unify permanent-tier immutability, project boundary, retired-node
purge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Five-task TDD plan for write-path slice A soft-retire:
1. graphdb_attr seeds the boolean `retired` marker (+ seeded_nrefs).
2. graphdb_mgr retire_node/1 + unretire_node/1 (tier-1 set_retired_/3 over
   the transaction seam; lazy retired-nref cache).
3. graphdb_mgr get_node/1 hides retired nodes ({error, retired}).
4. graphdb_instance refuses retired nodes as new participation.
5. Docs (Architecture, ontology-tree, TASKS).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tion

Per review of the soft-retire lifecycle test: the active assertion matches
any value=>true AVP (per the plan), which is not a false positive for a
fresh class. Add the attribute-specific predicate as an inline comment for
future hardening; behavior unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Block-new-participation guards: create_instance rejects a retired class
({class_retired, ClassNref}) or retired parent ({parent_retired, ParentNref});
add_class_membership rejects a retired class; add_relationship rejects any
retired endpoint ({endpoint_retired, Nref}).

+4 CT cases (110 instance, 432 total). Zero warnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update Architecture.md, ontology-tree.md, TASKS.md, and README to
reflect the completed soft-retire implementation: graphdb_mgr
retire_node/1 + unretire_node/1, graphdb_attr retired marker seed,
graphdb_instance retired-node participation guards. Test count
updated to 537 (432 CT + 105 EUnit).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- graphdb_mgr: reformat has_true_avp/1 anon fun to multi-line, matching
  the sibling is_retired_avp_present/2 style.
- graphdb_instance_SUITE: note that future retire-guard tests must be
  added to the maybe_set_runtime_phase/1 guard list.

No behavior change; graphdb_mgr_SUITE + graphdb_instance_SUITE green (147).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ok

@david-w-t david-w-t merged commit 428409c into davidwt-com:main Jun 18, 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