57%

§05 field read write edges

Goal

The writer/reader seam becomes queryable: a new field-use visitor pass (own namespace, never an L3-DDG extension) yields READS_FIELD/WRITES_FIELD, a bidirectional writers-of/readers-of surface, and turns the burden-registration probe green.

Implementation Sketch

  • New visitor (ExprField lvalue/rvalue classification): WRITES_FIELD on assignment position, READS_FIELD on expression position; nodes keyed by synthetic id per CPG convention; CfgBlock containment attribution; deliberately NOT an extension of the FieldInitWalker or the L3 DDG (deepseek F7).
  • Query surface: seam subcommand answering writers-of/readers-of for :Field owner_qn+name, traversing both directions.
  • Probe: the burden-registration seam (register_user_burden -> burdens map <- TypeRegistry::burden -> lookup_burden callers) is the committed acceptance case.

Spec References

  • intel_repo/extractor/cpg/src/binding.rs (FieldInitWalker boundary); intel_repo/CLAUDE.md L3/L6 limitations; the burden-registration seam: compiler_repo/compiler/ori_types/src/registry/types/mod.rs (register_user_burden, TypeRegistry::burden) + compiler_repo/compiler/ori_arc/src/lower/burden_lookup.rs

Work Items

  • New syn visitor pass emitting field-use facts (READS_FIELD/WRITES_FIELD), gated repo-wide via the shared CPG_SCOPE_PREFIXES_BINDER_COMMENTS SSOT (matching FieldInitWalker/comments.rs/attributes.rs — never the narrower aims-scoped CPG_SCOPE_PREFIXES); WRITES_FIELD classification covers BOTH direct assignment positions (self.field = …) AND mutating method-call sites on the field receiver (.entry(…).insert(…)/.or_insert(…) and equivalent collection-mutation idioms) — a bare-assignment-only classifier misses the burden seam’s actual write site (write_spec_to_idx’s burden_by_signature.entry(…).insert(…)), which would silently break the section’s own acceptance probe; READS_FIELD on plain expression position; nodes keyed by synthetic id per CPG convention; CfgBlock line-containment attribution used WHERE a CfgBlock exists, degrading to enclosing-function/owner_qn attribution (MATCH-not-fabricate, per comments.rs L10 / s-916f0932 precedent) for out-of-CFG-scope files such as the burden-registration acceptance seam; deliberately NOT an extension of the FieldInitWalker or the L3 DDG (deepseek F7); extractor_version bump.
  • Importer per the edge-class contract (per-file declarative diff, prune semantics declared); schema constraints; staleness rides the widened binder facet
  • Writer/reader query surface: writers-of / readers-of subcommands (or one seam subcommand) resolving a field to its writer and reader method sets bidirectionally by keying on :Field owner_qn+name — NEVER on :CfgBlock, which has zero rows for out-of-aims-scope files such as the burden-registration acceptance seam; KNOWN_SUBCOMMANDS + blurbs.
  • Burden-seam fitness probe green end-to-end (register_user_burden + write_spec_to_idx writers <-> TypeRegistry::burden + lookup_burden readers traversable both directions via the new writers-of/readers-of surface, appearing in scripts/intel-query.sh fitness —json’s corpus and reading green); add (a) a synthetic-fixture ingestion pin (READS_FIELD/WRITES_FIELD emitted for a self.f = x write, a self.f.entry(…).insert(…) mutating-call write, and a self.f read), (b) the live burden-seam bidirectional-traversal pin against the real graph, and (c) an L13 limitations-inventory entry documenting the CfgBlock-optional attribution plus the syntactic (non-type-aware) lvalue/rvalue classification boundary.

Fresh intel (regenerated)

This section adds a THIRD walker over the existing CPG substrate — a field-use pass emitting READS_FIELD/WRITES_FIELD on the already-repo-wide :Field nodes — deliberately NOT an extension of the two walkers that already touch fields (FieldInitWalker at binding.rs:326 produces constructor-site :FieldInit; DdgWalker at ddg.rs:67 produces lexical-name :DataFlowNode def/use). The one decisive constraint the graph surfaces: the acceptance seam lives OUTSIDE the CFG/DDG facet scope, so the walker’s “CfgBlock containment attribution” cannot be the primary key for the probe.

Decisions this package forces before any code is written:

  1. :Field is ALREADY repo-wide (binder facet, CPG_SCOPE_PREFIXES_BINDER_COMMENTS empty = repo-wide) — TypeRegistry.burden_by_signature (line 47) + collection_burdens (line 69) exist as :Field nodes TODAY. The new facet MUST ride that same repo-wide binder gate (per work-item w-61e261fc “staleness rides the widened binder facet”), NOT the aims-only CFG/DDG gate — else the burden seam has no field-use coverage. [JOIN] — see 3.3.
  2. The CFG/DDG facet does NOT cover the seam: MATCH (b:CfgBlock) WHERE b.file STARTS WITH 'compiler/ori_types/src/registry' returns 0. “CfgBlock containment attribution” therefore degrades to owner-qn attribution (the MATCH-not-fabricate pattern comments.rs L10 already uses) for out-of-CFG-scope files. The writers-of/readers-of query MUST key on :Field owner_qn+name, never on :CfgBlock. [JOIN] — see 3.4.
  3. The “burdens map” in the section prose is a CONCEPT, not a field: the concrete fields are burden_by_signature + collection_burdens + the per-entry types_by_idx[*].burden. The probe must resolve writers-of BOTH storage homes (register_user_burden -> write_spec_to_idx side-table + reverse-index) and readers-of BOTH (TypeRegistry::burden reads types_by_idx.burden OR collection_burdens; lookup_burden is the ori_arc reader). See 1 + 3.2.
  4. The section has NO depends_on and is independently workable; its sibling s-916f0932 (comment-ingestion-repo-wide) is the nearest structural precedent (a repo-wide binder-gated facet) — read it first. See 4.
["FieldInitWalker", "DdgWalker"]

DIG DEEPER

scripts/intel-query.sh status | python3 -c "import sys,json; r=[x for x in json.load(sys.stdin)['data']['repos'] if x['name']=='ori'][0]; print(r['facet_generations']['field-use'])"
sed -n '/## Code Property Graph/,/## Plan.Bug Graph Pipeline/p' intel_repo/CLAUDE.md | head -80

(full dossier: field-read-write-edges—s-16f6a8a2.intel.md)