Skip to content

feat(markdown): resolve code-span mentions into references edges - #3562

Open
AstroMined wants to merge 1 commit into
Graphify-Labs:v8from
AstroMined:feat/markdown-code-span-references
Open

AstroMined wants to merge 1 commit into
Graphify-Labs:v8from
AstroMined:feat/markdown-code-span-references

Conversation

@AstroMined

Copy link
Copy Markdown

Fixes #3561.

The markdown extractor's docstring promised a heading --references--> node edge for backtick names
but nothing implemented it, so an AST build produced no document-to-code edge.

extract_markdown now reports inline code spans (outside fences and frontmatter) as raw_calls
tagged language: "markdown", owned by the enclosing heading or the page node. A new
graphify/markdown_resolution.py registers a markdown_mentions language resolver that turns them
into references edges: path::Symbol[::member] resolves through the cited file's symbols
(EXTRACTED 1.0); a bare or dotted name resolves only to a unique callable code node (INFERRED 0.95).
Ambiguous, builtin, missing-file and non-callable mentions emit nothing. The shared cross-file call
pass skips markdown raw_calls so prose never produces calls edges. The stale docstring line is
replaced with the actual behaviour.

Tests: tests/test_markdown_code_spans.py covers span classification, raw_call ownership and line
pinning, end-to-end resolution (INFERRED, EXTRACTED, doc-relative path, ambiguous, missing file, no
calls from document nodes, no dangling edges), and cache round-tripping. uv run pytest and
uv run --frozen ruff check . are green apart from four test_backup_* cases in test_export.py
and four test_pathless_postgres_* cases in test_extract_cli.py, which fail identically on clean
v8.

The markdown extractor's docstring promised a heading --references--> node edge
when a backtick Name matches a known pattern, but nothing implemented it, so an
AST build produced no document-to-code edge at all.

extract_markdown now collects inline code spans outside fences and frontmatter as
raw_calls tagged language "markdown", owned by the heading they sit under (the
page before the first heading). A new markdown_mentions language resolver runs
after the id-remap passes and turns them into references edges: the explicit
path::Symbol[::member] form resolves through the cited file's symbols and is
EXTRACTED 1.0; a bare or dotted name resolves only when exactly one callable code
node carries that label and is INFERRED 0.95. Ambiguous names, builtins, missing
files and non-callable matches emit nothing. The shared cross-file call pass
skips markdown raw_calls so prose never emits calls edges.

Tests cover span classification, raw_call ownership, end-to-end resolution,
ambiguity, and cache round-tripping.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 3 advisory finding(s) below merit a look before merge.

Formal verification. No changes could be formally verified in this run.


Graphify review — findings

Adds a Markdown code-span mention pass that turns backtick-quoted symbol references (Widget, render(), pkg.Widget, src/mod.py::Widget::render) in headings and body prose into references edges from the citing heading (or the page, above the first heading) to the code node that defines the symbol. Path-qualified mentions resolve against the cited file, walking the :: chain through contains/method edges and emitting an EXTRACTED edge; bare mentions resolve only on a unique case-sensitive match among callable/type nodes, emitting an INFERRED (0.95) edge, and ambiguous names produce nothing. Mentions ride the raw_calls channel tagged language: "markdown" so the id-remap passes rewrite them, and the shared cross-file call pass skips them so a citation never becomes a calls edge; spans reading as files (setup.py), commands, or prose are filtered out during extraction.

Worth a look

  • Dotted bare mention with non-code extension misclassified as symbolgraphify/extractors/markdown.py:275 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Segment-aligned suffix match returns first of a single-element list but suffix strip is wrong for './' prefixesgraphify/markdown_resolution.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Relative Markdown paths with '..' can resolve to an unrelated suffixgraphify/markdown_resolution.py:79 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1978 functions depend on the 288 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract() — 591 callers, 44 callees
  • new: _rebuild_code() — 116 callers, 51 callees
  • new: extract_js() — 85 callers, 4 callees
  • new: extract_xaml() — 19 callers, 17 callees
  • new: dispatch_command() — 2 callers, 124 callees
  • new: _get_extractor() — 26 callers, 6 callees
  • new: extract_markdown() — 17 callers, 9 callees
  • new: run_pipeline() — 8 callers, 13 callees
  • …and 31 more — each is listed as a finding

Verification — 1978 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 1803 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

276 of 276 test file(s) selected (100%) via static blast radius.

Escalated to a full run for safety — the selection is not trustworthy on its own (see below). CI should run the whole suite.

  • tests/test_affected_cli.py — full-run-safety
  • tests/test_affected_member_seed.py — full-run-safety
  • tests/test_agents_platform.py — full-run-safety
  • tests/test_analyze.py — full-run-safety
  • tests/test_anthropic_custom_endpoint.py — full-run-safety
  • tests/test_antigravity_install.py — full-run-safety
  • tests/test_apm_fallback_version.py — full-run-safety
  • tests/test_architecture_doc.py — full-run-safety
  • tests/test_astro_extraction.py — impact, full-run-safety
  • tests/test_astro_import_ids.py — impact, full-run-safety
  • tests/test_atomic_canvas_export.py — full-run-safety
  • tests/test_atomic_version_stamp.py — full-run-safety
  • tests/test_atomic_writes.py — full-run-safety
  • tests/test_backend_env_isolation.py — full-run-safety
  • tests/test_backend_extras.py — full-run-safety
  • tests/test_benchmark.py — full-run-safety
  • tests/test_benchmark_raw_graph.py — full-run-safety
  • tests/test_build.py — impact, full-run-safety
  • tests/test_build_merge_dedup_scope.py — full-run-safety
  • tests/test_build_merge_hyperedges_and_prune.py — full-run-safety
  • tests/test_build_merge_shrink_guard.py — full-run-safety
  • tests/test_builtin_global_type_refs.py — impact, full-run-safety
  • tests/test_cache.py — full-run-safety
  • tests/test_callflow_html.py — full-run-safety
  • tests/test_cargo_introspect.py — full-run-safety
  • tests/test_carried_hyperedge_remap.py — full-run-safety
  • tests/test_case_sensitive_resolution.py — impact, full-run-safety
  • tests/test_charmap_encoding.py — full-run-safety
  • tests/test_chunking.py — full-run-safety
  • tests/test_cjs_module_extension.py — impact, full-run-safety
  • tests/test_claude_cli_backend.py — full-run-safety
  • tests/test_claude_md.py — full-run-safety
  • tests/test_cli_broken_pipe.py — full-run-safety
  • tests/test_cli_export.py — full-run-safety
  • tests/test_cli_help.py — full-run-safety
  • tests/test_cluster.py — full-run-safety
  • tests/test_codebuddy.py — full-run-safety
  • tests/test_community_hub_labels.py — full-run-safety
  • tests/test_community_labels_skill.py — full-run-safety
  • tests/test_confidence.py — full-run-safety
  • tests/test_corrupt_graph_json.py — full-run-safety
  • tests/test_cpp_nested_and_cli.py — impact, full-run-safety
  • tests/test_cpp_objc_cross_file_calls.py — impact, full-run-safety
  • tests/test_cpp_preprocess.py — full-run-safety
  • tests/test_cross_extension_reexport_self_cycle.py — impact, full-run-safety
  • tests/test_cross_language_call_resolution.py — impact, full-run-safety
  • tests/test_cross_repo_member_calls.py — impact, full-run-safety
  • tests/test_cross_repo_shared_types.py — full-run-safety
  • tests/test_csharp_call_site_generic_args.py — impact, full-run-safety
  • tests/test_csharp_enum_members.py — impact, full-run-safety
  • … and 226 more

changed code file(s) with no mapped test (graphify/markdown_resolution.py) — a coverage gap or a missing link — running the full suite rather than only the selected tests

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

Formal verification

Could not verify: Could not verify extract.

The verifier did not have enough to check extract, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `cache_root` is annotated `Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify extract\_markdown.

The verifier did not have enough to check extract\_markdown, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

· 2 grounded finding(s) anchored inline below; 37 more finding(s) on lines outside this diff (see the check run).

return None, [m.group(1)]


def extract_markdown(path: Path) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressionextract_markdown()

fans out to 9 callees (efferent coupling); 17 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

return calls


def resolve_markdown_mentions(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressionresolve_markdown_mentions()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

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.

Markdown extractor: code-span references promised in the docstring are not implemented

1 participant