ItemGraph 0.4.0-beta.1 (Fabric 1.21.1, GriefLogger 1.2.10 compatible)
Curse Maven Snippet
What's new
[0.4.0-beta.1] — 2026-10-06
First public beta of the ItemGraph 0.4 line. The standalone GriefLogger
1.2.10-1.21.1 feature-parity milestone (M8) is complete on both loaders, and
this release also carries the M9 admin UX, named-permission, privacy, and
reliability work delivered since 0.3.2. Four artifacts are published:
standard and -grieflogger-compatible jars for NeoForge and Fabric. Use the
standard jar when GriefLogger is absent; the compatible variants omit
ItemGraph's embedded SQLite driver for servers still running GriefLogger
1.2.10-1.21.1. ItemGraph is pre-1.0 and this build is a beta: the native-only
production cutover (M10, issues #71/#72) and the open M9 extension issues are
explicitly not claimed here.
Upgrade notes
- The database migrates automatically from schema V12 to V21 on first start.
Back up
itemgraph.db(or the configured network database) before upgrading; migrations run in order and preserve existing evidence. - Named
itemgraph.*permission nodes are new; operator level 2 remains the fallback, so existing servers keep working unchanged. Delegated permission setups must additionally grantitemgraph.auditfor/ig event,/ig explain,/ig trace, the flow browser, and location-sensitive lookups (kills, projectile throws/shots, chat and command provenance) — these queries are now denied without it. - New optional language setting (
general.languageon NeoForge,languageon Fabric) selects server-sideen_us,nl_nl, orzh_twmessage text; clients need no ItemGraph assets. - The event taxonomy is version 4.0.0; integrations reading ItemGraph event
IDs should review
docs/EVENT_TAXONOMY.mdbefore upgrading.
Fixed
Drop ground endpoint at rest position (#166, NeoForge): drop observations now record the
GROUNDnode where the item entity settles — on-ground, near-zero velocity, removal, or a five-second cap — instead of the eye-height spawn point. Same-spot drop→pickup pairs now share one ground node, so the entity-UUID continuity path ranks the real pickup (live-verified at confidence 0.9990 with anACTIVEinferred edge). The equivalent Fabric path keeps the defect; #166 stays open for it.Complete admin permission recipes (#153):
/ig help permissionsnow states the root requirement and root-only status/help access, gives separate copyable grants for lookup, trace, event detail, explanations, inspection/history, direct and inspector container views, audit, ingest, and optional import, and documents the extra audit node for chat/command provenance. It explains explicit denies, level-2 fallback, non-inheriting dotted nodes, and points to the exact command matrix without inventing provider-specific grant syntax.Honest craft and smelt evidence (#162): result-slot callbacks now preserve the observed output stack, quantity, fingerprint, actor, position, and event UUID as protected
UNRESOLVEDaudit evidence. They no longer invent ingredient fingerprints or create false trace edges. Long modded display metadata is safely truncated without changing the fingerprint. LegacyCRAFT/SMELTrows are historical-only unresolved evidence and no longer display a source-to-result arrow. The differential profile and replay normalizer recognize the new output-only event; expensive M9 replay/load/export checks remain deferred to milestone closeout. Help and the quick start explain the lookup and limits.First-time admin help/status UX (#153):
/ig help commandsis a compact task hub with topic continuation; focused lookup topics cover admin item commands, entity/projectile lifecycle, and supported transformations. Journey help defines OBSERVED, INFERRED, AMBIGUOUS, UNRESOLVED, and PROVENANCE_ONLY with source-correct follow-up paths and exact grants. Filtered lookup distinguishesobservation#NIDs accepted by/ig event Nfrom audit, transformation, and imported references that remain inline; trace/explain, GUI, and saved-page requirements are explicit. Sensitive-location and staff-activity lookup types enforceitemgraph.auditfrom the shared event taxonomy, including saved pages and filtered lookups. Section 4 demonstrates only a short read-only path; broad parser cases live in an explicitly non-executable test corpus so placeholder IDs and stateful/import commands are not presented as a runnable incident. Incident export remains marked unavailable until #37 ships.Projectile location privacy (taxonomy 4.0.0):
THROW_ITEMandSHOOT_ITEMexpose player coordinates, so direct, paged, and filtered audit queries now requireitemgraph.audit, asKILL_ENTITYand accepted projectile spawns already do. Taxonomy major version reflects the stricter privacy contract.Issue #33 command-to-item evidence links: admin and creative outcomes now list bounded UUIDs for accepted item observations, transformations, and unresolved before/after audit records.
/ig event event:<uuid>opens each evidence type under the existing event and audit permissions; transformation details distinguish the affected player/entity from the command actor. Outcomes sayLINKED,PARTIAL_LINK_LIST,UNRESOLVED_EVIDENCE_RECORDED, orNO_ITEM_EVIDENCE_RECORDEDaccording to the captured records.Flow-browser row labels (#146): display only the observed action or transformation kind in the numbered companion; internal parent, break, and evidence UUIDs remain out of the concise event label. Numbered companion entries map left-to-right to the first menu row, and each selectable item hover names its exact slot. Known transformation-related fingerprints use their item icon. The admin guide explains how to map entries to slots and read hovered detail-page fields.
Protected evidence query gating:
/ig event,/ig explain,/ig trace, and the flow browser now requireitemgraph.audittogether with their existing leaf permission before any query or candidate lookup. Async delivery, GUI pages/details, menu validity/clicks, and page-derived location tokens retain and recheck the complete permission set, preventing protected observation or inferred-edge metadata from leaking through candidates, counts, errors, or navigation. Explain hover detail is attached only to its inferred summary line; cited observation rows keep their observed wording.Issue #140 empty-container and unavailable-actor semantics: an empty successful snapshot now records only its zero-content completion, without an unresolved ground-drop relation.
CONTAINER_BREAK_UNRESOLVEDis taxonomy actorUNKNOWN; lookup labels missing player identity(actor unavailable)rather than attributing the event to a player. The redacted conformance report and validator now require drop-link outcomes only for nonempty breaks.Status capture and recovery clarity (#155):
/ig statusnow distinguishes disabled capture, active intake, recovery loading, recovery failure, and a stopped worker, and reports an unknown recovery count when the spool has not been read or could not be read. Runtime diagnostics print before asynchronous database statistics, so a failed stats query cannot hide capture and queue state. Help and the admin guide define the state meanings, counter units, reset windows where known, and safe next steps without inventing health thresholds.First-time admin workflows (#156–#158):
/ig help journeyslinks four detailed inspect, trace, nearby-audit, and filtered-lookup topics. Each gives exact permission nodes, evidence meaning, a follow-up command, and safe checks for empty results. Trace observations use numeric IDs;event:<uuid>is for related IDs from admin/creative outcome details. Ingest help describes GriefLogger sync as optional and native capture as automatic. The quick start adds complete permission bundles and documents shipped feature boundaries without transient PR/CI status.Unsupported or unknown transformation rows no longer appear as observed item-trace hops. Unified lookup keeps their evidence ID, source/result fingerprints, unresolved reason, and unknown quantity without rendering free-form legacy details that could look like a numeric quantity. Existing raw database rows are unchanged.
Issue #24 right-click inspector: NeoForge and Fabric now ignore off-hand right-clicks while inspection mode is active and resolve ordinary block clicks to the clicked-face neighbor. ItemGraph keeps its documented clicked-position behavior for functional blocks, and clicked-position support for modded
Containerblock entities is an extension; GriefLogger 1.2.10's implementation uses this fallback for functional blocks other than doors and containers. Inspection still consumes the interaction only when ItemGraph accepts the asynchronous history request.Issue #24 command packet test timing: aligned the NeoForge and Fabric GameTest outer limit at 4,000 ticks so fast headless tick progression cannot preempt the fixture's 10-second wall-clock durability deadline. This corrects the CI-only timeout while retaining the bounded failure deadline.
Issue #32 shutdown durability: shutdown waits are bounded at 5 seconds graceful plus 5 seconds after interruption for each database worker, 5 seconds for an ItemGraph-owned recovery-file writer, and 1 second for JDBC connection close. Startup replay and shutdown recovery-file I/O run on daemon workers, not the loader lifecycle callback. New events remain bounded in the normal queues during replay, and recovered rows are placed before them. A completed snapshot replays idempotently by
ingest_event_uuid; corrupt or unsupported primary recovery data is preserved, intake closes, and already-accepted records are saved to an adjacent.overflowrecovery file without replacing the primary. Both files replay after the primary file is repaired. If the filesystem does not finish a snapshot within its deadline, ItemGraph logs critical evidence risk and counts the outstanding records; a late daemon write may finish only if the process remains alive and the filesystem returns.Issue #32 performance evidence: correlation failures returned as result values now increment the failure counter. The MySQL and MariaDB CI probes now execute 20 registered
/ig lookupcommands alongside 20 raw-JDBC readers and 512 submitted events on both loaders, recording callback completion and p95/max latency. CI also enforces a 1,000 ms drain regression budget for the healthy NeoForge SQLite 10,000-event saturation fixture, based on five repeated local measurements.Issue #32 idle baseline: CI adds one-second live tick-hook no-input samples for both loaders against SQLite and worker-only samples against MySQL and MariaDB. The validator requires zero queue, persistence, lookup, correlation, rejection, and heartbeat work; reports compare durable observation, audit, and transformation row counts and capture heap at the sample boundary. Network-backend samples do not represent live server ticks or production budgets.
Expired lookup-page cleanup (#24): following an expired explicit
/ig page <page> <session>link now removes the player's empty page-session map. Fabric dispatcher coverage exercises both command roots, invalid/expired sessions, cross-player tokens, denied permission, and error-only output; NeoForge page-session regressions remain green.
Added
Offline server-side localization (#136): NeoForge
general.languageand Fabriclanguageselect ItemGraph-owneden_us,nl_nl, orzh_twresources before database initialization. NeoForge and Fabric reject unsupported values with ageneral.languagediagnostic; rendered chat/menu text uses server-side literals, so clients need no ItemGraph assets or network access. English per-key fallback preserves unknown/future messages. The key fallback inventory is empty fornl_nlandzh_tw; 125 authored source phrases use the tested English fallback, including detailed help topics. Evidence IDs, item IDs/names, timestamps, quantities, evidence-class tokens, and click command payloads remain data values. The exact GriefLogger 1.2.10-1.21.1 fixture has no locale inventory;en_us,nl_nl, andzh_tware only verified in pinned 26.2 source research, andzh_cnis source-only/not selectable.First-use admin workflows (#148–#150): bare
/ignow presents a five-message task-first overview;/ig help guideopens the server setup guide,/ig help commandsgroups command paths, and/ig help permissionsdocuments exact access nodes. The guide puts loader choice, server-only installation, permissions, and safe test-world verification before investigations, then explains query surfaces, confidence, and concrete evidence gaps. README and the local CurseForge draft now agree on platform and permission behavior.Structured query chat and scannable flow-browser rows (#138, #146): query output keeps the stable
QueryFormattertext while adding bounded hover details and player-only dimension-aware navigation bound to the exact originating permission set. Flow-browser timelines and candidate lists use up to nine rows per page, further capped byquery.max_page_size, and send numbered companion lines with observed/inferred class, safe identity, event kind, and UTC time where recorded; missing identities and unresolved targets are labeled explicitly. No raw NBT or component payloads are exposed. These authored labels resolve through the selected ItemGraph locale, and evidence values remain data.Named command permissions (#137):
/igand/itemgraphkeep vanilla permission level 2 as the fallback, while exactitemgraph.*nodes let providers delegate lookup, paging, inspection, traces, events, explanations, audits, GUI browsing, ingest, and import separately. Explicit deny overrides operator status. NeoForge uses registered permission nodes; Fabric embeds Permissions API 0.3.1 without requiring an external permission manager. Async results, inspection clicks, every flow-menu action, and protected audit lookup/page continuations recheck the required node set. Lookup-only access cannot read chat, command, administrative-item, or creative-action audit records./ig help permissionsexplains delegation.Player-broken container contents (#140): successful Fabric and NeoForge player breaks now capture the exact non-empty block-entity slots as per-slot
REMOVE_ITEMevidence with canonical fingerprints and stable parent/child event IDs, plus a deterministic link to the matchingBREAK_BLOCKaudit row. The completion summary and its slot rows persist atomically in one transaction; a slot-write failure rolls back the whole group. The destroyed container is the source and the destination remains unknown; the player is not assumed to receive the contents. Empty snapshots have no unresolved drop-link row; nonempty parent, unresolved drop-link, and slot rows share bounded queue admission. Tests include empty, one-stack, full single-chest, and double-chest-half cases. Nonempty drop relationships remain unresolved until an authoritative hook can establish them. The NeoForge result wrapper is narrowly scoped toServerPlayerGameMode.destroyBlockbecause its 1.21.1 break event runs before mutation. The additive event IDs advance the independent event taxonomy to 2.1.0.Standalone historical player-name resolution (#31): native
PLAYER_JOINevidence now populates ItemGraph's UUID-keyedig_player_name_historytable. Native audit user filters and suggestions resolve names recorded on prior joins to every matching UUID without requiring GriefLogger. Imported GriefLogger history remains an optional source. The native-only replay now includes redactedPLAYER_JOINsignals so CI marks both the sessions and usernames categories exercised without exporting names or UUIDs. Names changed during an online session are not captured until a later join.Issue #31 exact-release action-table replay: the redacted ItemGraph-only NeoForge and Fabric reports now include separate
chatsandcommandscategories, one player quit, one consumed item, one durability break, and oneCRAFTtransformation, in addition to the existing movement, projectile, block, container, and entity evidence. Each loader report validates 25 events against the pinned release profile and represents all six GriefLogger event tables. Chat and command text, player names, UUIDs, absolute world coordinates, and database row IDs remain excluded from the reports. Other ItemGraph extensions stay explicitly assigned to their existing issues.Issue #31 pickup coordinate rationale: Documented the loader-specific drop hooks used by the replay fixtures. NeoForge's patched two-argument
Player.dropfiresItemTossEvent; its three-argument overload bypasses that hook. Fabric captures the accepted entity through its three-argument drop path. The normalized replay records pickup Y=2 on NeoForge and Y=1 on Fabric; the exact fixture-level cause remains unverified because both adapters store block coordinates and the report omits sub-block positions.Issue #31 replay queue evidence: NeoForge and Fabric native replay reports now include each ingestion queue's export-time depth, fixed capacity, and the cumulative server-wide rejected-event counter since service initialization. The normalizer rejects over-capacity queue depths, capacity drift, or any server-wide rejection since service initialization. Raw report schema is v5 and normalized comparison schema is v6; this complements the separate 8,000-event peak-backlog/load probe.
Issue #31 unresolved historical actions: GriefLogger action IDs are checked against the source table's action map without narrowing; raw payloads and unresolved reasons retain larger IDs exactly, so table- invalid, oversized, and non-integral malformed IDs remain importable as unresolved evidence, with original values retained in the raw payload. The lookup projection no longer exposes an unknown or missing source action's amount or item-type ID as event semantics. The immutable import ledger retains the action, complete payload, and component bytes; the projection reports quantity
0, nosubject_id,UNRESOLVED, and the original raw-byte hash. Added an importer regression fixture with action ID999and malformed component bytes that also verifies the source database remains byte-for-byte unchanged.Issue #31 source contradiction fixtures: added a machine-readable corpus for the required-radius documentation/source difference, GriefLogger's stored chat/command rows versus its lookup surface, and newer Ender enum values absent from the exact 1.21.1 release writers. CI checks the pinned source identity, duplicate-free case IDs, exact owner issues and decisions, and declared Java-method or documentation anchors.
Issue #31 release-contract coverage inventory: CI now emits a redacted sidecar beside each native-only NeoForge and Fabric replay. Schema v2 lists every compatibility-registry action and all eleven exact-release database table families, with replay counts separate from exact-release writer dispositions. It identifies the absence of a dedicated native username-history table as an uncovered standalone query category. The report distinguishes unobserved categories from unsupported release writers without claiming full runtime parity. Tests and CI do not package distributable mod jars.
Issue #127 native-only default: NeoForge and Fabric no longer inspect a
database.dbfile for GriefLogger data during normal operation. Read-only source sync and historical import require the explicitgrieflogger_integration_enabled=truesetting. Native capture, storage, correlation, and queries remain independent, and scheduled native-only ticks do not report the disabled source sync as an error.Issue #32 operational metrics and queue probes:
/ig statusreports redacted enqueue, persistence, query, correlation, queue-pressure, component decode-cache, and heap aggregates. CI emits validated 14-day reports for both loaders on SQLite and on disposable MySQL/MariaDB, plus a NeoForge queue saturation/shutdown durability report. Network probes run 20 read-only ledger count queries across four readers against 512 synthetic events; the shutdown probe persists all 10,000 accepted events in bounded worker batches and counts one rejected over-capacity event explicitly. Reports contain aggregate values without event or player identifiers. The real adapter workloads and staging-derived production budgets remain open under #32.Issue #32 report provenance: performance report fixtures record
grieflogger_runtime_stateasabsent,present, orunavailableinstead of treating an uninitialized NeoForge JUnit mod list as proof of absence. Loader GameTests assert GriefLogger is absent; CI rejectspresentreports and limitsunavailableto NeoForge JUnit-only probes. The report schema is version 2.Issue #32 malformed-component workload: the SQLite correlation probes feed one malformed serialized component payload to the canonicalizer 500 times and record the first-decode and total elapsed time. CI requires one negative-cache insertion, 499 cache hits, and the same opaque unresolved fingerprint for every repetition. The decoder diagnostic now names the serialized component payload, independent of the optional historical importer.
Issue #33 administrative item evidence: both loaders capture
/give,/clear,/itemslot mutations, creative inventory slot changes, accepted/giveoverflow, and negative-slot creative drops at vanilla mutation boundaries. Creative block placement and destruction store authoritativeCREATIVE_BLOCK_RESULTevents and explicitly report zero player-inventory quantity delta. Paired GameTests cover creative placement and destruction plus linked invalid-item failure outcomes. Attempts, outcomes, and observed deltas share mutation IDs;/item modifypersists explicit canonical transformations, while creative packet and/item replacestack changes persist separate removal and creation deltas without inferring a causal transformation. Bounded or failed/giverecipient snapshots retain an unresolved outcome and cannot fall through to player-drop attribution; accepted overflow still records exact ground-output evidence by target UUID, while rejected overflow records item, quantity, fingerprint, and entity identity as unresolved evidence, including canceled tosses. Unrelated players' drops remain independently capturable during the command./item ... from block/entityevidence retains the copied-from slot and stack without treating a copy as source removal. Nested/execute asoutcomes keep the original issuer as actor and store a differing effective entity as execution-context evidence. The implementation leaves clone versus pick-block undifferentiated, records empty slots as unresolved before/after evidence, keeps staff activity private, suppresses raw item-command and/executearguments, and contains capture exceptions without changing vanilla results.Issue #35 shared event taxonomy: introduced the versioned
EventTaxonomyfor native audit, item observation, and transformation IDs. Audit command types and unified lookup aliases now use the shared registry. Definitions specify evidence class, capture reliability, endpoint and quantity semantics, actor status, privacy class, loader support, evidence-ID contract, aliases, and owning issue. #55–#57 event families and stable unresolved reason codes are listed as planned until loader adapters and fixtures prove support. This is a taxonomy version only.Creative transformation evidence boundary: taxonomy
2.0.0retainsCREATIVE_ITEM_TRANSFORMfor classification but marks it unsupported on both loaders withCREATIVE_TRANSFORM_CAUSE_NOT_REPORTED. Creative slot packets prove separate quantity deltas, not conversion between item fingerprints, so the ID retainsUNRESOLVEDevidence withUNKNOWNquantity and no longer appears in lookup suggestions.Issue #31 native replay reports: NeoForge and Fabric GameTests export six durably verified item movement/projectile rows plus ten allowlisted audit events, including
PLACE_BLOCK,INTERACT_BLOCK_ATTEMPT, andKILL_ENTITY, with namespaced entity/blocksubject_id, and a count-onlyAuditServicewhole-database invariant summary to redacted raw schema-v5 reports when CI setsITEMGRAPH_DIFFERENTIAL_REPORT_DIR. The mock GameTest establishes the target world states, then dispatches each registered loader event or placement capture handler exactly once. The audit uses one read-only transaction snapshot and rejects over-capacity observations, mismatched per-edge SOURCE/DESTINATION sums, unsupported roles, and allocations detached from direct evidence, matching fingerprints/actions, or actor endpoints. It rejects edge timestamps that do not match forward source and destination evidence. The CI normalizer independently rejects non-zero violation counts; Java and Python gates pin action/subject pairs and the three new block-action positions. Normalized schema-v6 output retains the validated count-only summary, preserves subject IDs, and exposes the issue-linked exception gate. Registry compatibility version ism8.12.0. These native-only reports do not claim a GriefLogger comparison or complete #31's paired replay, staging soak, or rollback gates.Issue #31 parity fixture correction: the replay report includes only the successful source-water bucket pickup among
BREAK_BLOCKrows. It filters by the exact fixture position andminecraft:water, excluding the separate synthetic water-source/lava-result guard probe, which cannot occur in an actual GriefLogger bucket-pickup writer path. The current raw report is schema-v5 and normalized output is schema-v6.Issue #31 issue-linked differential exceptions: normalized schema-v6 keeps every report difference visible, classifies only profile-declared native extensions as expected only when their source table also matches the pinned policy, and links each to its owning issue and stable reason code.
equivalentremains false when any difference exists; CI passes only when there are no unexplained differences. Quantity, timestamp, endpoint, privacy, and evidence-class mismatches remain unexplained. Registry compatibility version ism8.12.0.Issue #30 queue flush cadence: both loader configs now expose
ingestion.queue_frequency_ticks/queue_frequency_ticks, defaulting to 20 and accepting 1–100 ticks to match GriefLogger'squeueFrequency. Both server end-tick adapters signal the bounded background writer; queue submissions still do no database work on the server thread. ItemGraph raw evidence retention stays indefinite. Added live queue-flush GameTests to both loaders' registered CI suites.Issue #24 Fabric inspector command execution:
FabricItemGraphCommandsParityTestnow executes both command roots through enabled, already-enabled, status, disabled, already-disabled, and toggle-back states, asserting the per-player state and exact chat receipts. Permission-denied execution emits no success receipt and does not enable inspection. This is dispatcher-level coverage; it does not replace the pending vanilla-client command replay.Issue #27 bucket fluid removal evidence: NeoForge and Fabric now record a
BREAK_BLOCKaudit row when a server bucket pickup successfully removes a source fluid block. Both hooks wrapBucketPickup.pickupBlock, require a non-empty returnedBucketItem, preserve the source block coordinates, and use the returned bucket's contained fluid for the fluid block ID. They write no item quantity observation. Shared loader GameTests verify the durable row and quantity ledger boundary. Registry compatibility version ism8.9.0.Issue #27 action registry and exact-release writer matrix: registry
m8.8.0now records the pinned source enum and ID for all 18 GriefLogger actions plus the exact1.2.10-1.21.1writer result. CI rejects malformed boolean/float IDs and duplicate JSON keys, and checks action-specific JVM enum-field accesses in both official loader artifacts.INTERACT_BLOCKis compatible at the attempt-only boundary proven by #74;INTERACT_ENTITYhas no action ID or writer in the target release and remains a separately labeled ItemGraph extension per #75. Ender actions remainunsupported-no-writerper #76.Issue #27 projectile runtime conformance: NeoForge and Fabric GameTests now call the real
Projectile.shootFromRotationandServerLevel.addFreshEntityboundaries for one snowball and one arrow. Read-only SQLite assertions require one quantity row per attempt, player-to-unknown endpoints, matching source event IDs in the legacy audit projections, accepted-spawn item/action identity, distinct accepted-spawn evidence, and no extra quantity rows for the test player or mutation of prior quantity rows. The test uses embedded mock players and does not establish vanilla-client transport or bow-ammunition accounting.Issue #27 item movement runtime conformance: both loader GameTests now exercise real chest-menu quick-moves and player inventory removal/drop/pickup. The shared read-only SQLite fixture requires exactly one
ADD_ITEM,REMOVE_ITEM,DROP_ITEM, andPICKUP_ITEMrow with expected registry IDs, quantities, endpoints, coordinates, metadata fingerprints, session intervals, and shared dropped-entity identity across drop/pickup. NeoForge uses the two-argumentPlayer.droppath that postsItemTossEvent; Fabric exercises its acceptedServerPlayer.drop/ServerLevel.addFreshEntitymixin path. Both assert that inventory counts before and after each transfer. The fixture also requires the exact spawned entity UUID, rejects any fifth observation for the replay player regardless of action/source, and verifies prior quantity rows remain unchanged. Ground evidence coordinates may differ by one block across the server tick. The remaining #27 writer actions still need paired runtime fixtures.Issue #75 cross-loader interaction evidence: non-armor-stand callbacks now carry stable
target_support=callback_onlyandtarget_support_reason=ENTITY_CLASS_UNSUPPORTED_FOR_RESULTmetadata, while armor-stand rows identify their supported method-result boundary. Callback-level denied/unresolved outcomes remain recorded where observed. NeoForge and Fabric isolated server GameTests send entity-use packets through each loader's server handler for unsupported-entity attempts and armor-stand boot equip/unequip. They separately call inheritedArmorStand.interactto verify itsPASSreturn hook and persisted unresolved method result. Both tests compare the completeig_observationsrow snapshots before and after, and check the same normalized audit query andQueryFormatteroutput used by/ig lookup. CI runs both loader GameTests without creating distributable mod jars.Issue #76 Ender action compatibility: the release fixture validator now checksum-verifies both published 1.2.10-1.21.1 jars and finds no Ender action constant field references outside
ItemAction.class; itsvalues()calls are limited to the genericActionscatalog and the enum's ownfromIddecoder, and the only externalfromIdcaller isItemHistory.<init>reconstructing stored rows. The registry marks both GriefLogger actionsunsupported-no-writerusingNO_WRITER_IN_EXACT_1_2_10_1_21_1_RELEASE; existing ItemGraph session net deltas stay labeled asITEMGRAPH_INTERNALextensions. Regression coverage checks duplicate opens, reconnects, partial signed counts, atomic queue rejection/retry including orderly shutdown under one shared five-second retry deadline, opaque component redaction, no-net sessions, and restart persistence. Registry compatibility version ism8.7.0.Issue #24 command contract:
/igand/itemgraphexpose the same level-2 command tree; GriefLogger's published directname.valuelookup syntax, six filter names and one-letter aliases, required cubic radius, five-filter limit, AND combination, ten-row page default, per-player pages, and page navigation are covered across NeoForge and Fabric tests. The selected published-doc radius requirement is explicit because GriefLogger 26.2 source accepts no-radius lookup. Output retains ItemGraph evidence labels and provenance;/gland/griefloggerremain unregistered.Issue #24 lookup filter boundary coverage: Fabric and NeoForge now parse an exactly-five-filter valid lookup and execute both
/igand/itemgrapherror cases through both direct andlookup filtersforms for missing radius, malformed and invalid radius tokens, unknown and duplicate filters, include/exclude conflicts, and a sixth filter. Both roots return the same exact single failure before query output; runtime behavior is unchanged.Historical user filter completion (#24):
/ig lookup user.<name>suggestions now include distinct names from imported GriefLoggerusersandusernamesreference rows as well as online players. ItemGraph reads its own preserved provenance rows asynchronously through the bounded read-only query worker, caches the result for 30 seconds, and skips malformed payloads. Read-only queries now instrument JDBC statements with a five-second timeout and cancellation; SQLite keeps its progress-handler and connection-interrupt support.Issue #26 block inspector evidence timeline:
/ig inspectnow opens one exact-position, globally paginated timeline for block audit events, container item deltas, transformations, and imported GriefLogger event rows. Double chests and doors resolve to their physical target cells without duplicate rows; a container observation matches either endpoint, so a transfer is found even when the player endpoint is stored first. Schema V19 records block-removal supersession links for native and imported interaction evidence while keeping every source row immutable. Imported row links use a SHA-256 key and retain the full source key. Ordinary lookup still returns superseded rows with the replacement evidence ID and reason. Both loaders consume an inspection click only after the bounded asynchronous query is accepted; queue rejection preserves normal gameplay. Live client/server matrix verification remains pending.Issue #30 configuration baseline: added cross-loader page-cap, bounded queue idle-poll/batch, native-capture, server-only, and indefinite-retention settings and a configurable 30-second MySQL/MariaDB connection keepalive on the background worker.
/ig statusreports backend, schema, effective query cap, connection timeout, index policy, and queue controls while omitting database paths and raw exception details. A temporary loopback-only NeoForge 21.1.248 server and Fabric Loader 0.16.9 server both confirmed that/reloadleaves startup-snapshot controls unchanged and restart applies representative edited values; both status responses showed page cap 25, timeout 5,000 ms, indexes enabled, and the expected queue controls. The cross-loader config tests check Fabric startup snapshots and NeoForge worker-stop application; rejected live application leaves the query cap unchanged. CI exercises the worker heartbeat against both MySQL and MariaDB. GriefLogger queue cadence equivalence remains unverified because its scheduled flush and ItemGraph's signal-driven queue have different semantics. Local NeoForge-only startup, schema upgrade, and 2,000-record SQLite worker load passed. Seedocs/CONFIGURATION.mdanddocs/TEST_PLAN.md.Issue #30 blank database path validation: NeoForge and Fabric now reject empty or whitespace-only ItemGraph and GriefLogger database paths with the exact config key before applying operational settings or opening ItemGraph storage. NeoForge startup CI probes verify both empty paths fail before DB initialization and preserve the invalid TOML values.
Issue #30 configuration error keys: network database settings now report their
general.*key when rejecting blank host/name/username, invalid port or timeout, and unsupported TLS mode. Fabric also names invalid database backend and boolean settings with the shared NeoForge config key. Errors do not expose database passwords or echo invalid backend text. Network connection logs and failures omit endpoint fields and raw JDBC exception text.Issue #30 remove unused debug logging setting: removed the advertised
debug_loggingconfig value because it did not enable any logging behavior on either loader. The configuration reference no longer describes a no-op control.Issue #30 fail-closed NeoForge config validation: numeric settings now reject invalid types and out-of-range values with the full config key before NeoForge can clamp them; string, boolean, and integer values retain their native config metadata. Fresh GameTest startup probes confirm
query.max_page_size=101andgeneral.database_port=0fail before database initialization and remain unchanged in TOML. This closes the reproduceddatabase_port=0to1normalization gap; full invalid-config matrix coverage across both loaders remains open.Issue #30 Fabric numeric config parity: Fabric now validates all seven documented integer settings, including database port and connection timeout even when SQLite is selected. Unit coverage accepts both endpoints and rejects below-range, above-range, and non-integer values with the full config key and rejected input. Non-numeric malformed-config combinations and GriefLogger queue-cadence evidence remain open.
Evidence and queue failure handling: legacy topology migrations now copy observations, referenced fingerprint values, and raw payloads into
ig_legacy_observation_evidencebefore removing obsolete endpoint projections. Failed transformation batches are returned to the bounded retry queue, included in pending counts, and explicitly counted as evidence loss if shutdown cannot persist them.Idempotent ingestion retries: schema V18 adds unique queue-event UUIDs to observation, transformation, and audit ledgers. A retry after a database commit whose acknowledgement was lost now resolves to the original row instead of duplicating evidence or quantity.
Configurable storage indexes (issue #29):
storage.use_indexeson NeoForge anduse_indexesin Fabric's properties file now default totrue. On every startup, ItemGraph creates any missing optional lookup indexes or drops only those optional non-unique indexes when disabled. Existing databases support either toggle direction after restart; required unique deduplication indexes remain active, and MySQL/MariaDB retain indexes needed to support foreign keys. Invalid Fabric boolean values fail config loading with the offending key named.
Changed
- Entity interaction outcomes (#75): both loaders retain entity-use attempts with target UUID when available, held item ID/count/fingerprint hash, and explicit completion coverage. Armor-stand return hooks cover the
ArmorStand.interactAtoverride and inheritedEntity.interactfallback (required because 1.21.1ArmorStandinheritsinteract): consuming results becomeINTERACT_ENTITY_COMPLETED,FAILbecomesINTERACT_ENTITY_DENIED, and fallbackEntity.interactPASSbecomesINTERACT_ENTITY_UNRESOLVEDwithout claiming the full pipeline ended. NeoForge callback cancellations are retained. Fabric decorates the aggregateUseEntityCallbackinvoker once, preserving callback order and short-circuiting while recording one final non-PASSresult, including cancellations before or after ItemGraph's listener. Non-armor-stand targets have no method-result hook; their rows identifytarget_support=callback_onlywith stable reasonENTITY_CLASS_UNSUPPORTED_FOR_RESULT, while observed callback-level denied/unresolved results remain recordable. Removed the prior pre-use armor-stand equip/unequip quantity rows because they could claim item movement before the game accepted it. A handled return is not proof of equipment movement. The exact GriefLogger 1.2.10-1.21.1 artifact has no entity-interaction writer; this ItemGraph behavior is documented as an extension, with the newer 26.2 source behavior kept distinct. - Block interaction evidence parity (#74): native block-interaction capture on Fabric and NeoForge now follows GriefLogger 1.2.10-1.21.1's main-hand gate and exact 28-class functional-block set. Rows remain
INTERACT_BLOCK_ATTEMPTbecause the reference hook runs before use results; moddedContainerinspection remains separate from this action mapping. - Long GriefLogger primary keys: imported source keys over 191 Unicode codepoints now use a deterministic SHA-256 key over length-framed UTF-8 key values so MySQL/MariaDB composite indexes accept them without delimiter ambiguity; the immutable payload preserves all original key fields. The historical ledger and normalized lookup projection use the same key, while pre-change SQLite checkpoints resume using their original key format.
- Loader runtime hardening: Fabric pickup capture no longer exposes a non-private mixin helper or nested record that Mixin remaps as a Minecraft inner class. Native lookup event types now use vanilla literal command nodes, preserving direct GriefLogger filter syntax while allowing NeoForge and Fabric operators to receive the command tree without a disconnect. Connected-player staging replays verified one durable throw and shoot row plus one accepted spawn audit row for each loader.
- One storage contract for SQLite and MySQL/MariaDB: ItemGraph now exposes validated backend settings on NeoForge and Fabric, runs the shared migrations and JDBC queries through one dialect layer, preserves SQLite partial-dedup semantics with generated sentinel columns on network databases, and bundles MariaDB Connector/J 3.5.7. CI provisions MariaDB 10.11 and MySQL 8.0 for the same migration, upsert, constraint, and read-only integration contract. Issue #29 remains open until hosted CI completes its full acceptance run.
- Network storage safety: non-loopback MySQL/MariaDB connections configured
with
database_ssl_mode=disablenow emit an explicit plaintext-transport warning; production deployments should useverify-fullorverify-ca. - Compatibility profile m8.2.1: projectile action rows now preserve observed stack counts without claiming a landing location; the direct lookup projection is paired with accepted observation enqueueing and the unified lookup suppresses it only when the shared raw event identity is durably persisted.
- Observation retry integrity: failed internal observation transactions are retained in the bounded queue with backoff, and shutdown failures are counted as dropped evidence instead of being reported as persisted.
- GriefLogger parity profile: pins the audited GriefLogger 26.2 source commit, records all 18 source actions and 11 source tables, separates ItemGraph-only transformations and automation from true source actions, and links the M8/M9 delivery issues for unresolved parity and audit++ work.
- Compatibility profile CI gate: adds the read-only
tools/validate_grieflogger_profile.pycheck, a canonical source-profile SHA-256, pinned source-file citations, and milestone-reference validation before the loader build runs. - Exact GriefLogger 1.21.1 release fixture: pins the official Fabric and NeoForge
1.2.10-1.21.1artifact IDs, URLs, byte sizes, SHA-1/SHA-256/SHA-512 digests, manifests, Java 21 mixin contracts, embedded JDBC versions, action IDs, schema columns, commands, configuration defaults, and inspector behavior. CI can download and verify both published jars withtools/validate_grieflogger_release_fixture.py; no GriefLogger jar is vendored. - Compatibility profile contract hardening: the CI validator now locks every published action's ItemGraph mapping, status, evidence class, quantity semantics, and loader set, and it requires the filtered-lookup owner issue (#25) in the parity and milestone records.
- Native entity and Ender coverage: NeoForge and Fabric now retain server-side
INTERACT_ENTITYattempts, and Ender Chest menu sessions emit signedADD_ITEM_ENDER/REMOVE_ITEM_ENDERdeltas to a durable player-owned external-inventory node without polling or permanent item UUIDs. Successful entity-outcome parity remains tracked by #27. - Read-only historical import foundation:
GriefLoggerHistoricalImporternow preserves all 11 pinned GriefLogger tables in ItemGraph-owned provenance tables with source/schema fingerprints, bounded resumable checkpoints, deterministic primary-key/rowid/hash identities, opaque binary payload retention, unknown-action reasons, supported-schema rejection, independent writer batches, durable failed-run counts, and idempotent replay. It never writes to the GriefLogger database; projecting the generic historical ledger into unified lookup remains tracked by #28, while #25 covers the completed native/normalized lookup contract. - Historical GriefLogger lookup projection: migration v15 adds a rebuildable
ig_grieflogger_lookupindex foritems,containers,blocks,sessions,chats, andcommands. Imported rows preserve table/key provenance, actor identity with historical username resolution, level/material/entity references, action IDs, quantities, opaque-byte hashes, and explicit unresolved status. Unified filtered lookup now merges the projection, while exact source/table/key provenance lookup exposes reference and identity rows without treating them as item quantities. - Historical projection recovery: repeat imports revisit checkpointed source rows to backfill a missing v15 projection, and unified timelines select the latest completed source snapshot while retaining older snapshots for exact provenance review.
- Native audit ledger: ItemGraph now has its own
ig_audit_eventsschema and native NeoForge/Fabric capture paths for supported player session, chat, block, entity, and command-attempt actions. NeoForge records consume and durability-break item actions in the quantity-flow ledger; projectile actions now use quantity observations in both loaders. Fabric post-execution command results remain tracked indocs/GRIEFLOGGER_PARITY.md. - Audit reliability: NeoForge block use is labeled
INTERACT_BLOCK_ATTEMPTuntil a completion event exists, capped audit pages report the effective page after offset limits, and transient audit database failures retry with bounded exponential backoff and rate-limited error logs. - Command evidence labeling: NeoForge command hooks now store
COMMAND_ATTEMPT; the underlyingCommandEventis a pre-execution callback, so ItemGraph no longer presents it as completed execution. - Fabric command coverage: the Fabric adapter now records
COMMAND_ATTEMPTat Minecraft'sCommands.performCommandboundary through a narrowly scoped server mixin, matching NeoForge's pre-execution semantics without claiming command success. - Projectile evidence boundary: the canonical
THROW_ITEM/SHOOT_ITEMquantity row is emitted at the GriefLogger-compatibleshootFromRotationattempt boundary; accepted player-owned spawns remain separate raw evidence with no landing or projectile-UUID claim. - Projectile retry and acceptance integrity: projectile attempt rows now persist a durable source event identity for idempotent worker retries, and both loaders emit accepted-spawn evidence only after
addFreshEntityreturns true; accepted audit details do not claim a quantity. - Audit retry identity: migration v16 adds source-event deduplication for native audit rows, and projectile attempt/accepted evidence now persists that identity in
ig_audit_eventsas well as the quantity ledger. - NeoForge staging run: the ModDev server now includes the shared
commonandcoresource sets, allowing a GriefLogger-absentrunServersmoke to load ItemGraph and its mixins before a release build. - Fabric placement coverage: the Fabric adapter now records completed
BlockItem.placeactions asPLACE_BLOCKaudit evidence through a server-only return hook; failed and non-block interactions remain excluded. - Fabric ground-flow coverage: the Fabric adapter now records normal player drops, vanilla player-death inventory drops, and full or partial pickups through server-only hooks. It requires the
addFreshEntityacceptance result, preserves the returnedItemEntityUUID, labels death-time rowsDEATH_DROP, captures custom item entities accepted duringServerPlayer.die, uses the returned entity stack count for drops, and uses the before/after count delta for pickups. - Fabric container sessions and automation: server menu initialization and close hooks reuse the shared interval tracker for block containers and double chests, orderly server shutdown flushes active session deltas before database close, and
HopperBlockEntitytransfers emit bounded netHOPPER_INSERT/HOPPER_EXTRACTobservations with unknown endpoints. Modded automation remains a tracked adapter gap. - Fabric transformation coverage: crafting, furnace-family smelting, and anvil rename/repair results are captured at their server result-take boundaries and written to the shared transformation ledger with canonical source/result fingerprints.
- Fabric item-action coverage: completed eat/drink actions now use a server-only
LivingEntity.completeUsingItemcompletion hook at the method's return boundary and preserve the original stack across nested calls; durability breaks are captured at the authoritativeItemStack.hurtAndBreakshrink boundary. The bounded capture records live in a non-mixin helper so Fabric remapping cannot turn nested records into invalidLivingEntityconstructors. Canceled or non-consumable uses do not createCONSUME_ITEMevidence. - Fabric consume-capture stability: HEAD and RETURN callbacks now match a consume invocation by a stable caller class/method marker and stack depth, excluding the target method's differing source line. Stale or ambiguous nested markers are discarded instead of pairing a completed use with another invocation's original stack.
- Fabric inspector parity:
/ig inspectnow opens the shared read-only container flow browser through Fabric'sUseBlockCallback, with permission checks, accepted-query cancellation, rejected-query fallback, and disconnect cleanup matching NeoForge behavior. - Block inspection:
/ig inspectnow opens an asynchronous, paginated exact-coordinate audit history on both loaders for initial left-clicks and non-container right-clicks, cancels the gameplay action before native capture (including rejected lookups), and ignores repeated left-click hold/abort packets. Double-chest/door logical-target aggregation remains tracked by #26. - Published lookup syntax:
/ig lookupnow accepts the documented direct GriefLogger filter form (action...,user...,include...,exclude...,time..., andradius...) with token-aware suggestions and the published ten-row default;/ig lookup filters ...remains an explicit ItemGraph spelling. - Lookup completion parity: direct lookup completion now offers published one-letter filter aliases, action values from GriefLogger 26.2 plus ItemGraph-supported actions, registered item identifiers, and online player names; it stops suggesting duplicate/conflicting filters and enforces the five-filter completion limit. Offline historical username completion remains tracked by #24.
- Fabric command parity matrix: the Fabric test suite now exercises the shared
/igand/itemgraphBrigadier contract for direct and explicit GriefLogger filter syntax, standalone paging, inspect toggles, and published suggestions alongside the NeoForge command matrix. - Logical inspector targets:
/ig inspectnow queries both physical halves of a valid double chest or door in one bounded, globally ordered audit page, preserving one row per stored event and exact dimension filtering. - Stable double-chest session anchors: new container sessions choose one deterministic physical anchor for both halves and register the other half as an alias on Fabric and NeoForge, preventing future clicks on opposite halves from creating divergent ItemGraph container nodes. Reopening a former partner position after a chest split retires the stale alias before creating the new watch; overlapping old and new watches close against their own keys and share capability credits so topology changes cannot manufacture player movement.
- Native entity-interaction lookup:
/ig lookup INTERACT_ENTITYnow selects the native audit-event path on both loaders, matching the existing server-side interaction-attempt evidence and the shared filtered lookup action vocabulary. - Unified GriefLogger-style filtered lookup:
/ig lookup filtersnow accepts up to fivename.valuefilters for native audit, item-flow, and transformation actions, user names or UUIDs, included/excluded subjects, recent time, and a required bounded cube radius around the issuing player. One bounded asynchronous merge reads native audit events, observations, transformations, and importedGRIEFLOGGERobservations while preserving source and prefixed evidence IDs. Include/exclude conflicts and unsupported actions are rejected before the read-only query. - Interactive audit paging:
/ig lookup pagenow returns permission-checked Previous/Next chat controls that rerun the same bounded filters. - Modrinth publication gate: tagged releases and the Modrinth-only retry workflow now check both project API endpoints before publishing. A non-2xx response disables Modrinth steps cleanly while GitHub and CurseForge publication continue; a later release or manual retry becomes eligible after both endpoints return successful responses.
- GriefLogger component decode handling: undecodable historical
DataComponentPatchrows no longer emit a per-row WARN or repeat the same codec failure for every duplicate row while its entry remains in the bounded cache. ItemGraph keeps the raw BLOB, records an opaque SHA-256 fingerprint so distinct payloads do not collapse into one item-ID fingerprint, and emits one DEBUG diagnostic per payload and registry context. Replacing the server registry context clears the cache and permits a retry. - Unsupported GriefLogger database guard: a readable SQLite file is now checked for the complete supported
items,containers,users,levels, andmaterialsschema before ingestion. Unrelated or empty SQLite files are skipped with one informational message instead of repeated missing-table warnings. - Projectile action parity: both loaders now record
THROW_ITEMandSHOOT_ITEMat the sameProjectile.shootFromRotationHEAD attempt boundary used by GriefLogger, while accepted player-owned spawns are retained asPROJECTILE_SPAWN_ACCEPTEDevidence without duplicating quantity flow. Compatibility artifacts remain gated by the other unresolved action families. - Lookup case compatibility: native
/ig lookuppreserves GriefLogger's case-insensitive event parsing without a custom command-tree serializer; literal aliases cover suggestions and the greedy fallback handles mixed-case root, player, paged, and near queries, including legacyALLspellings. - Source-event collision handling: native UUID-derived numeric source IDs now compare the producer UUID across both evidence tables and probe deterministic salted IDs when a distinct event collides, preserving paired observation and audit rows even when their raw payload details differ.
All Relations
- All Relations
- Embedded Library
- Optional Dependency
- Required Dependency
- Tool
- Incompatible
- Include