Skip to content

feat(guarantee): RFD-75 connascence-of-value — version-ref/coord/REFERS_TO + value-lockstep guarantee - #450

Open
Disentinel wants to merge 1 commit into
mainfrom
rfd-75-connascence-value-lockstep
Open

feat(guarantee): RFD-75 connascence-of-value — version-ref/coord/REFERS_TO + value-lockstep guarantee#450
Disentinel wants to merge 1 commit into
mainfrom
rfd-75-connascence-value-lockstep

Conversation

@Disentinel

Copy link
Copy Markdown
Owner

Motivation

The 0.4.0→0.4.1 saga exposed a bug class CI never caught: a value duplicated across N places that must move together drifted. It bit us twice:

  1. @grafema/cli optionalDeps pinned @grafema/grafema-* at 0.3.29 while the meta-package + published binaries were 0.4.0 → silent wrong-binary install.
  2. rfdb-server binary self-reported 0.4.0 inside the @grafema/grafema-linux-x64@0.4.1 package → runtime "version mismatch" warning on every analyze.

This is Connascence of Value (Fowler's "shotgun surgery"): grep catches it poorly, a graph catches it naturally. Rather than bolt bash onto grafema check (a category error — a build-artifact property is not a code-graph property, and an RCE surface), we model the coupling as graph facts and assert it with the existing Datalog guarantee engine. Static connascence detection is a genuine Grafema wedge: the graph sees what must change together.

The reusable coord / ref / REFERS_TO pattern

Three graph entities, value-agnostic:

  • version:coord — the logical thing that must agree (a dependency name, or release).
  • version:ref — each physical occurrence. value / locus / coord ride the node metadata JSON.
  • REFERS_TO edge — each ref → its coord.

One Datalog guarantee covers all of it (.grafema/guarantees.yaml, value-lockstep): any two refs to one coord with different values → violation.

Wiring in this PR:

  • packages/util/src/enrichers/versionRefEnricher.ts — emits one version:ref node per repo-static locus: each package.json version (coord release), each @grafema/* dep/optional/peer pin (coord = the dep name), the git tag, the CHANGELOG top entry. Writes via direct addNodes (deterministic ids <file>::version:ref::<locus>), never BatchHandle (which would delete pre-existing nodes in the touched files). Wired into analyzeAction.ts.
  • packages/rfdb-server/src/derive/stdlib/version_coords_nodes.dl + version_refs_edges.dl — the paired node-pack-then-edge-pack split (mirrors js_http_routes): the nodes pack mints one version:coord per distinct coord (meta(coord), exclusive/provenance-scoped); the edge pack joins ref↔coord by coord name as committed EDB and derives REFERS_TO (additive, shared vocabulary). Registered in stdlib.rs STDLIB_PACKS and the orchestrator STDLIB_RULE_PACKS at the registry tail, strict nodes→edges order.
  • packages/types/src/{nodes,edges}.tsVERSION_REF/VERSION_COORD node types + REFERS_TO edge type + the VersionRefNodeRecord/VersionCoordNodeRecord/RefersToEdge records.

Note: the value-lockstep rule reads value via the derive-engine node_attr builtin (a bound point-probe), not attr — value/locus/coord live in the node metadata JSON, not as RFDB top-level columns, so attr would yield zero rows. R and R2 are bound by the two REFERS_TO generator legs before node_attr runs.

Verify results

  • Rust unit tests (packages/rfdb-server, derive::stdlib): all 3 pass.
    • version_coords_nodes_mints_one_per_distinct_coord — one coord per distinct value, refs dedup.
    • version_refs_edges_joins_refs_to_coords_by_name — every ref REFERS_TO its own coord, no cross-link.
    • value_lockstep_guarantee_trips_on_drift_and_includes_binary_reftrips on drift, both 0.4.0 bugs reproduced (cli@0.3.29 vs meta@0.4.0 optionalDeps skew + a binary 0.3.29 vs package.version 0.4.0 ref), passes on lockstep with 0 false-positives, and an externally-ingested binary.<name> ref participates with no rule change.
  • @grafema/types, @grafema/util, @grafema/cli all build clean (tsc, no errors).
  • Pre-commit lint + handler tests green (22/22).

OPS-zone follow-on

The binary --version ref is a runtime property of a built artifact — not in the graph until the binary is executed. The release pipeline runs <binary> --version and ingests the output as a version:ref fact pre-grafema check; after that the lockstep rule asserts over source+binary refs uniformly. The graph side participates uniformly today — a binary.<name> ref REFERS_TO the same coord as package.version with no rule change (proven by the binary-ref test). Only the release-hook ingest itself is the OPS follow-on; no engine change required there.

Linear: RFD-75 — https://linear.app/grafemadev/issue/RFD-75/rfd-connascence-of-value-via-graph-coordrefrefers-to-lockstep

🤖 Generated with Claude Code

DO NOT MERGE — Vadim reviews.

…RS_TO + value-lockstep guarantee (catches the 0.4.0 drift class)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 1, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/stdlib.rs
packages/rfdb-server/src/derive/stdlib/version_coords_nodes.dl
packages/rfdb-server/src/derive/stdlib/version_refs_edges.dl
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 2, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/stdlib.rs
packages/rfdb-server/src/derive/stdlib/version_coords_nodes.dl
packages/rfdb-server/src/derive/stdlib/version_refs_edges.dl
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Grafema-AI-Ops

Copy link
Copy Markdown
Collaborator

🚫 QA precheck REJECT (attempt 3, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/stdlib.rs
packages/rfdb-server/src/derive/stdlib/version_coords_nodes.dl
packages/rfdb-server/src/derive/stdlib/version_refs_edges.dl
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Grafema-AI-Ops

Copy link
Copy Markdown
Collaborator

🚫 QA precheck REJECT (attempt 4, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/stdlib.rs
packages/rfdb-server/src/derive/stdlib/version_coords_nodes.dl
packages/rfdb-server/src/derive/stdlib/version_refs_edges.dl
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

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.

2 participants