M3 + M4 + M5 closeout; retire TASKS-HIGH.md#13
Merged
david-w-t merged 5 commits intodavidwt-com:mainfrom May 9, 2026
Merged
Conversation
graphdb_attr:create_relationship_attribute/3 now writes both attribute nodes and all four compositional arc rows inside a single Mnesia transaction. Previously the forward and reciprocal nodes were created in separate transactions; if the second aborted, the database was left with an orphan forward attribute and no usable reciprocal. New private helper do_create_relationship_attribute_pair/3 allocates the 2 node nrefs and 4 arc-id nrefs outside the transaction (avoiding side-effects on retry) and writes 6 rows in one txn. Test: create_relationship_attribute_pair_atomic asserts the row deltas on `nodes` and `relationships` after a successful pair creation are exactly +2 and +4 respectively, and that both nodes have exactly one parent->child arc into them under nref 8. Tests green: 146 CT + 64 EUnit = 210. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
graphdb_instance:add_relationship now runs an explicit validation pass
before resolving classes/templates and writing arcs. Five new failure
modes, all returning structured {error, _} tuples:
- {source_not_found, Nref}
- {target_not_found, Nref}
- {characterization_not_found, Nref}
- {reciprocal_not_found, Nref}
- {characterization_not_an_attribute, Nref, ActualKind}
- {reciprocal_not_an_attribute, Nref, ActualKind}
- {target_kind_mismatch, ExpectedKind, ActualKind}
The four endpoint reads run in one mnesia:transaction. target_kind is
sourced from the seeded `target_kind` literal-attribute (graphdb_attr);
the nref is fetched once at graphdb_instance init via
graphdb_attr:seeded_nrefs() and cached in a new gen_server state
record. Arc-label nodes that lack a target_kind AVP (relationship-
type bucket nodes, legacy data) skip the kind check.
The state record is a clean break from the previous `[]` carrier; only
the new validation needs it, but threading it through add_relationship
keeps the gen_server signature consistent.
Tests: +5 CT cases under the `relationships` group covering missing
source/target, non-attribute characterization, non-attribute
reciprocal, and target_kind mismatch (target_kind=class vs. instance
target). 151 CT + 64 EUnit = 215 green.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
graphdb_instance:add_relationship/6 (S, C, T, R, TemplateNref,
{FwdAVPs, RevAVPs}) -> ok | {error, _} accepts per-direction user AVPs
and stamps them on the connection rows alongside the auto-applied
Template AVP. Per-direction (asymmetric) is required by §5: connection
metadata such as provenance, confidence, weights, and validity windows
is direction-specific.
The Template AVP stays at index 0 of each row's avps list; user AVPs
follow. /4 and /5 stay non-breaking and pass {[],[]} to /6 internally.
write_connection_arcs is updated to take {FwdAVPs, RevAVPs} and the
gen_server message form gains AVPSpec as a 7th tuple element.
Tests: +3 CT cases under the `relationships` group:
- add_relationship_stamps_user_avps -- user AVP is present alongside
Template AVP on the forward row
- add_relationship_avps_are_per_direction -- a forward-only AVP must
not leak into the reverse row, and vice versa
- add_relationship_default_avps_empty -- /4 still produces a row
with exactly the Template AVP
154 CT + 64 EUnit = 218 green.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mark M3, M4, M5 RESOLVED in TASKS-MEDIUM.md with status blocks describing the API and test additions for each. Bump README and ARCHITECTURE test counts (209 -> 218; 145 CT -> 154 CT). Update graphdb_attr_SUITE row to mention atomic reciprocal pair, and graphdb_instance_SUITE row to mention M3 validation and M5 per-arc AVPs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
All H-tasks (H0a-H0e, H1+H2, H3, H4+H5) landed in PRs davidwt-com#10 and davidwt-com#12. Per the task-file retirement workflow (close-out PR keeps the file with finish markers; the next PR opens with a removal commit), drop the file and prune cross-references in CLAUDE.md, README.md, ARCHITECTURE.md, arcs-authoritative.md, TASKS-MEDIUM.md, and the two app-level CLAUDE.md files.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bundles the first three medium-severity tasks plus the retirement of
TASKS-HIGH.md.8fa16a8) —graphdb_attr:create_relationship_attribute/3now writes the reciprocal attribute pair (2 nodes + 4 compositional arcs) in a singlemnesia:transaction/1. Mid-pair aborts can no longer leave an orphan half-pair. Nrefs are allocated outside the transaction so retries don't burn nrefs.bc32c5c) —graphdb_instance:add_relationshipvalidates endpoints in one transaction before resolving classes/templates and writing arcs. Returns structured errors for missing source/target/char/recip, non-attribute char/recip, andtarget_kindmismatch. The seededtarget_kindliteral-attribute nref is fetched once atinit/1and cached in gen_server state.3c4300f) — newadd_relationship/6 :: (S, C, T, R, TemplateNref, {FwdAVPs, RevAVPs})accepts per-direction user AVPs and stamps them on the two connection rows alongside the auto-applied Template AVP./4and/5stay non-breaking and pass{[], []}through internally.88735c7) — TASKS-MEDIUM marks M3, M4, M5 RESOLVED; README + ARCHITECTURE refreshed to 218 tests (154 CT + 64 EUnit).b457636) —TASKS-HIGH.mdremoved (all H-tasks landed in PR H3 + H4 + H5 closeout; project copyright refresh #12); cross-references pruned in CLAUDE.md, README.md, ARCHITECTURE.md, arcs-authoritative.md, TASKS-MEDIUM.md, and the two app-level CLAUDE.md files.Tests
graphdb_attr_SUITE:create_relationship_attribute_pair_atomic(M4)graphdb_instance_SUITEcases underrelationshipscovering M3 reject pathsgraphdb_instance_SUITEcases underrelationshipscovering M5 (add_relationship_stamps_user_avps,add_relationship_avps_are_per_direction,add_relationship_default_avps_empty)Test plan
./rebar3 compileclean./rebar3 ct— 154 cases passing./rebar3 eunit— 64 cases passinggraphdb_mgr:verify_caches/0clean in every CTend_per_testcase