This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/master by this push:
     new 47f5980111 Add a TinkerGraph playbook to tinker-review for memory and 
storage changes
47f5980111 is described below

commit 47f5980111f7862ff61b4feb96ff262320a15d8e
Author: Stephen Mallette <[email protected]>
AuthorDate: Wed Oct 21 21:08:46 2026 +0000

    Add a TinkerGraph playbook to tinker-review for memory and storage changes
    
    Assisted-by: Claude Code:claude-opus-5-5
---
 .skills/tinker-review/SKILL.md                 |   1 +
 .skills/tinker-review/playbooks/tinkergraph.md | 110 +++++++++++++++++++++++++
 2 files changed, 111 insertions(+)

diff --git a/.skills/tinker-review/SKILL.md b/.skills/tinker-review/SKILL.md
index 05556edbeb..b1ae237140 100644
--- a/.skills/tinker-review/SKILL.md
+++ b/.skills/tinker-review/SKILL.md
@@ -72,6 +72,7 @@ select the domain playbooks in two passes:
    - `gremlin-dart/`, `gremlin-go/`, `gremlin-python/`, `gremlin-dotnet/`, 
`gremlin-js/`, `gremlin-javascript/` → `playbooks/glv.md`
    - `gremlin-core/` with new step patterns → `playbooks/new-step.md`
    - `gremlin-driver/`, `gremlin-server/`, `gremlin-util/` → 
`playbooks/driver-server.md`
+   - `tinkergraph-gremlin/` on a `master` base branch → 
`playbooks/tinkergraph.md`
    - Small change set with linked issue → `playbooks/bug-fix.md`
    - `gremlin-language/` or `*.g4` → `playbooks/grammar.md`
    - Deletion-heavy change set (removes a feature/module/dependency; 
`listDeleted` returns entries) → `playbooks/removal.md`
diff --git a/.skills/tinker-review/playbooks/tinkergraph.md 
b/.skills/tinker-review/playbooks/tinkergraph.md
new file mode 100644
index 0000000000..506ba947bb
--- /dev/null
+++ b/.skills/tinker-review/playbooks/tinkergraph.md
@@ -0,0 +1,110 @@
+# Playbook: TinkerGraph
+
+## Context
+Changes under `tinkergraph-gremlin/`. TinkerGraph is the reference 
implementation, so
+its behaviour is what users and providers assume Gremlin means. It comes in 
three
+configurations, and each part of this playbook says which it applies to:
+- `TinkerMemoryGraph` — in memory, no transactions, no storage. What 
`TinkerGraph.open()`
+  returns.
+- `TinkerStorageGraph` without a storage engine — in memory with transactions
+  (optimistic, fail-fast on conflict); retains nothing across a restart.
+- `TinkerStorageGraph` with a storage engine — the same transactions, with 
each commit
+  written to a store directory before it is applied in memory and replayed on 
reopen.
+
+Work out which configurations the changed code reaches before reading further: 
code
+shared by both graph classes (elements, properties, indexes, id managers, the 
common
+base) reaches all three; the transaction and commit path reaches both 
`TinkerStorageGraph`
+configurations; storage engines and store files reach only the last.
+
+Applies only when `meta.baseBranch` is `master`. On `3.7-dev` and `3.8-dev` 
TinkerGraph has
+none of these configurations, so set this playbook aside there.
+
+## Enrich
+None applies beyond `general.md`; persistence-specific relationships are read 
from the
+source during Inspect rather than written to the graph.
+
+## Inspect
+**All configurations:**
+- Configuration — keys a configuration accepts but silently ignores. A key 
that asks for
+  durability and is dropped turns persistence into data lost on restart.
+- Features — what each configuration advertises (transactions, persistence) 
against
+  what it does.
+- Shared code — a change to element or graph code shared by both classes is a 
change to
+  every configuration; check it was written for both, not only the one the PR 
targets.
+
+**Transactional (`TinkerStorageGraph`, with or without a storage engine):**
+- Element identity — what a caller holds versus what is committed. A reference 
obtained
+  through an index, kept across a commit, or held across `clear()` must not be 
the shared
+  committed object, or writes through it skip the transaction.
+- Isolation — a write is visible to other threads only after commit and is 
undone by
+  rollback, whatever path found the element (id lookup, index, edge endpoint).
+- Concurrency — element locking fails fast with a `TransactionException`; 
check that new
+  code neither blocks where it used to fail nor fails where it used to proceed.
+- Commit path — everything a commit changes (elements, indexes, containers) is 
applied
+  together or not at all, and cleanup after commit, rollback or `clear()` 
cannot drop
+  another transaction's element.
+
+**Storage engine (`TinkerStorageGraph` with a storage engine):**
+- Integrity — every store file carries a check that detects damage, and every 
size the
+  format declares is bounded before it is allocated.
+- Crash points — at each step of a commit, compaction or `clear()`, the files 
left on
+  disk reopen to a state the caller was told about. Atomic replacement (write, 
sync,
+  rename) for whole files; nothing acknowledged is lost.
+- Torn tail versus damage — the rule that discards an incomplete final record 
must not
+  also discard a complete, acknowledged one that was damaged.
+- Fail-stop — after an I/O failure the graph stops accepting commits, and a 
commit that
+  became durable but was not applied in memory reports what it is.
+- Locking — the directory lock holds against another process for the graph's 
whole
+  life. Closing any descriptor on the lock file drops a POSIX lock; Windows 
locks are
+  mandatory and behave differently.
+- Recovery and settings — a recovery open writes nothing; settings that shape 
the data
+  are fixed when the store is created.
+- Interleavings — compaction against concurrent commits, `clear()` against open
+  transactions.
+
+## Verify
+- Run the battery against every configuration the changed code reaches (see 
Context),
+  not only the one the PR is about. Transactional scenarios (commit, rollback, 
a second
+  thread's view) apply only to `TinkerStorageGraph`.
+- With a storage engine, include a close and reopen in the same scenario: a 
change that
+  is correct in memory can still persist the wrong state.
+- Layer 1 (embedded, through the built Console); a fresh store directory per 
scenario.
+- Open each configuration explicitly: `TinkerGraph.open()` is 
`TinkerMemoryGraph`;
+  `TinkerStorageGraph.open()` has no storage engine; for a storage engine pass 
a
+  configuration with `gremlin.tinkergraph.storage` and
+  `gremlin.tinkergraph.storage.directory`.
+
+With a storage engine, when the change reaches storage:
+- Crash consistency — write, halt the JVM with `Runtime.halt` mid-operation, 
reopen in a
+  new JVM, and compare what survives with what was acknowledged.
+- Second process — two JVMs on one directory; the second must be refused for 
as long as
+  the first is open. Confirm against the operating system's lock table (for 
example
+  `/proc/locks`), not only the JVM's.
+- Damage — corrupt each store file in turn (a flipped byte, a truncation, a 
file from
+  another store) and check each is reported as damage rather than opened or 
silently
+  cut.
+- Recovery — a recovery open leaves every file byte-identical.
+
+## Interpret
+- A test that models another process with a second channel or graph in the 
same JVM — a
+  test-quality finding: in-JVM locks and caches make it pass where two 
processes would
+  not.
+- A crash-window test whose assertion cannot fail for the reason it states — a
+  test-quality finding.
+- Durability, fsync or timing observations made on tmpfs — meaningless; a 
durability
+  claim tested only there is untested.
+- Do not propose running the standard structure, feature or computer suites 
with a
+  storage engine (tp-kwk.41): they exercise Gremlin semantics, which storage 
does not
+  change within an open graph.
+- An isolation or identity defect found through a storage engine — high, and 
check
+  `TinkerStorageGraph` without an engine too: the transactional code is 
shared, so the
+  same bug usually exists there.
+- A shared-code change tested against one configuration only — an open 
question per
+  untested configuration it reaches.
+- `checks.coverageGaps` on storage code — the tests that reach it are often
+  fault-injection or reopen tests that the static call graph misses; read 
those before
+  naming a gap.
+
+## Escape
+- if the change alters the on-disk format of an existing store with no version 
check or
+  migration — "Format change without a version check: existing stores may open 
as damage or as wrong data"

Reply via email to