Skip to content

M3 + M4 + M5 closeout; retire TASKS-HIGH.md#13

Merged
david-w-t merged 5 commits intodavidwt-com:mainfrom
david-w-t:develop
May 9, 2026
Merged

M3 + M4 + M5 closeout; retire TASKS-HIGH.md#13
david-w-t merged 5 commits intodavidwt-com:mainfrom
david-w-t:develop

Conversation

@david-w-t
Copy link
Copy Markdown
Contributor

Summary

Bundles the first three medium-severity tasks plus the retirement of TASKS-HIGH.md.

  • M4 (8fa16a8) — graphdb_attr:create_relationship_attribute/3 now writes the reciprocal attribute pair (2 nodes + 4 compositional arcs) in a single mnesia: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.
  • M3 (bc32c5c) — graphdb_instance:add_relationship validates endpoints in one transaction before resolving classes/templates and writing arcs. Returns structured errors for missing source/target/char/recip, non-attribute char/recip, and target_kind mismatch. The seeded target_kind literal-attribute nref is fetched once at init/1 and cached in gen_server state.
  • M5 (3c4300f) — new add_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. /4 and /5 stay non-breaking and pass {[], []} through internally.
  • Docs (88735c7) — TASKS-MEDIUM marks M3, M4, M5 RESOLVED; README + ARCHITECTURE refreshed to 218 tests (154 CT + 64 EUnit).
  • Retirement (b457636) — TASKS-HIGH.md removed (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

  • 218 green: 154 Common Test + 64 EUnit
  • New CT cases:
    • graphdb_attr_SUITE:create_relationship_attribute_pair_atomic (M4)
    • 5 graphdb_instance_SUITE cases under relationships covering M3 reject paths
    • 3 graphdb_instance_SUITE cases under relationships covering M5 (add_relationship_stamps_user_avps, add_relationship_avps_are_per_direction, add_relationship_default_avps_empty)

Test plan

  • ./rebar3 compile clean
  • ./rebar3 ct — 154 cases passing
  • ./rebar3 eunit — 64 cases passing
  • graphdb_mgr:verify_caches/0 clean in every CT end_per_testcase
  • CI green on this PR

david-w-t and others added 5 commits May 8, 2026 21:03
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.
@david-w-t david-w-t merged commit 41c0dba into davidwt-com:main May 9, 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