feat(guarantee): RFD-75 connascence-of-value — version-ref/coord/REFERS_TO + value-lockstep guarantee - #450
Open
Disentinel wants to merge 1 commit into
Open
feat(guarantee): RFD-75 connascence-of-value — version-ref/coord/REFERS_TO + value-lockstep guarantee#450Disentinel wants to merge 1 commit into
Disentinel wants to merge 1 commit into
Conversation
…RS_TO + value-lockstep guarantee (catches the 0.4.0 drift class) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Owner
Author
|
🚫 QA precheck REJECT (attempt 1, base=main). QA gate |
Owner
Author
|
🚫 QA precheck REJECT (attempt 2, base=main). QA gate |
Collaborator
|
🚫 QA precheck REJECT (attempt 3, base=main). QA gate |
Collaborator
|
🚫 QA precheck REJECT (attempt 4, base=main). QA gate |
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.
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:
@grafema/clioptionalDeps pinned@grafema/grafema-*at0.3.29while the meta-package + published binaries were0.4.0→ silent wrong-binary install.rfdb-serverbinary self-reported0.4.0inside the@grafema/grafema-linux-x64@0.4.1package → 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, orrelease).version:ref— each physical occurrence.value/locus/coordride the node metadata JSON.REFERS_TOedge — each ref → its coord.One Datalog guarantee covers all of it (
.grafema/guarantees.yaml,value-lockstep): any two refs to one coord with differentvalues →violation.Wiring in this PR:
packages/util/src/enrichers/versionRefEnricher.ts— emits oneversion:refnode per repo-static locus: eachpackage.jsonversion(coordrelease), each@grafema/*dep/optional/peer pin (coord = the dep name), the git tag, the CHANGELOG top entry. Writes via directaddNodes(deterministic ids<file>::version:ref::<locus>), neverBatchHandle(which would delete pre-existing nodes in the touched files). Wired intoanalyzeAction.ts.packages/rfdb-server/src/derive/stdlib/version_coords_nodes.dl+version_refs_edges.dl— the paired node-pack-then-edge-pack split (mirrorsjs_http_routes): the nodes pack mints oneversion:coordper distinct coord (meta(coord), exclusive/provenance-scoped); the edge pack joins ref↔coord by coord name as committed EDB and derivesREFERS_TO(additive, shared vocabulary). Registered instdlib.rsSTDLIB_PACKSand the orchestratorSTDLIB_RULE_PACKSat the registry tail, strict nodes→edges order.packages/types/src/{nodes,edges}.ts—VERSION_REF/VERSION_COORDnode types +REFERS_TOedge type + theVersionRefNodeRecord/VersionCoordNodeRecord/RefersToEdgerecords.Note: the
value-locksteprule readsvaluevia the derive-enginenode_attrbuiltin (a bound point-probe), notattr— value/locus/coord live in the node metadata JSON, not as RFDB top-level columns, soattrwould yield zero rows. R and R2 are bound by the twoREFERS_TOgenerator legs beforenode_attrruns.Verify results
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_ref— trips on drift, both 0.4.0 bugs reproduced (cli@0.3.29 vs meta@0.4.0 optionalDeps skew + a binary0.3.29vs package.version0.4.0ref), passes on lockstep with 0 false-positives, and an externally-ingestedbinary.<name>ref participates with no rule change.@grafema/types,@grafema/util,@grafema/cliall build clean (tsc, no errors).OPS-zone follow-on
The binary
--versionref is a runtime property of a built artifact — not in the graph until the binary is executed. The release pipeline runs<binary> --versionand ingests the output as aversion:reffact pre-grafema check; after that the lockstep rule asserts over source+binary refs uniformly. The graph side participates uniformly today — abinary.<name>ref REFERS_TO the same coord aspackage.versionwith 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.