Skip to content

fix(skill): stamp _origin on the semantic tier so update cannot delete it (#2843) - #3110

Open
abhay-codes07 wants to merge 1 commit into
Graphify-Labs:v8from
abhay-codes07:fix/semantic-origin-stamp
Open

fix(skill): stamp _origin on the semantic tier so update cannot delete it (#2843)#3110
abhay-codes07 wants to merge 1 commit into
Graphify-Labs:v8from
abhay-codes07:fix/semantic-origin-stamp

Conversation

@abhay-codes07

Copy link
Copy Markdown
Contributor

Closes #2843.

The problem

build._is_ast_tier reads _origin when present and otherwise guesses the tier from the shape of source_location: L<line> means AST. extract() stamps its own items _origin: "ast"; nothing stamped the semantic side — not the runbook's Part C merge, not extract_corpus_parallel, not the CLI's merge.

So a semantic node's tier was decided by what its location happened to look like. A subagent writing "§4" for a document with section numbers was fine; one writing "L12" for a document without them produced a node that read as AST. The next graphify update — which replaces the AST tier of every re-extracted code file — treated it as that file's stale AST and deleted it. On the reporter's 21-document run: 8 of 21 files lost, 133 nodes and 236 edges, on a commit that touched one file.

The change

Three sites now stamp _origin: "semantic" explicitly, with setdefault so an existing stamp is never overwritten:

  1. The runbook's Part C merge (core, aider and devin fragments) — the block the reporter's run went through — stamps every semantic node and edge before merging with the AST side. The 134 generated skill artifacts are regenerated, the expected/ snapshots blessed, and the new lines registered as a sanctioned monolith diff (_is_semantic_origin_stamp_fix_line) so the round-trip validator keeps guarding everything else. All five skillgen validators pass.
  2. llm.extract_corpus_parallel stamps its result via a small _stamp_semantic_origin(result), so library callers and the CLI's fresh results carry it.
  3. The CLI's AST+semantic merge stamps sem_result as a whole, which also covers semantic-cache hits written before this change.

Hyperedges are untouched: they are semantic by construction and _is_ast_tier never looks at them.

Tests

tests/test_semantic_origin_stamp.py — 6 tests: the shape fallback is shown to be the trap (an unstamped L12 doc node reads as AST); the stamping helper marks nodes and edges and keeps existing marks; each of the three runbooks' Part C python is extracted from its fragment, unescaped as the shell would, and executed against an AST/semantic pair — the merged output must carry ast on the code node and semantic on the doc node and its edges; and a build_merge re-extraction of the code file keeps the stamped document node. With the fix reverted, 3 fail (the helper test skips). test_skillgen, the test_llm* suites, test_extract_cli and test_build_merge* are unchanged; the full suite matches the v8 baseline.

Companion #2844 (Step 9 manifest stamping) is being handled in #2966 and is not touched here.

…e it (Graphify-Labs#2843)

build._is_ast_tier reads `_origin` when present and otherwise guesses the
tier from the SHAPE of source_location: 'L<line>' means AST. extract()
stamps its own items 'ast'; nothing stamped the semantic side. A subagent
(or a backend) that reports 'L12' for a document section therefore made
that node read as AST, and the next `graphify update` — which replaces the
AST tier of every re-extracted code file — deleted the document's whole
semantic layer. On the reporter's 21-document corpus: 8 files, 133 nodes
and 236 edges lost on a commit that touched one file.

Three sites now say so explicitly, with setdefault so an existing stamp
is never overwritten:

  * the runbook's Part C merge (core, aider and devin fragments) stamps
    every semantic node and edge before merging — the block the reporter's
    run went through;
  * llm.extract_corpus_parallel stamps its result (_stamp_semantic_origin),
    so library callers and the CLI's fresh results carry it;
  * the CLI's AST+semantic merge stamps sem_result as a whole, which also
    covers semantic-cache hits written before this change.

The skillgen artifacts are regenerated, the expected/ snapshots blessed,
and the new Part C lines registered as a sanctioned monolith diff.
Copilot AI lite review requested due to automatic review settings August 26, 2026 11:24

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@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.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

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


Graphify review — findings

Stamps _origin: "semantic" on every node and edge of a semantic extraction so the tier is recorded explicitly rather than inferred from source_location shape, which misread doc sections carrying L<line> numbers as AST and let the next graphify update delete them (#2843). Adds _stamp_semantic_origin in llm.py, applies it at the end of extract_corpus_parallel and before the merge in dispatch_command, and mirrors the same stamping step into the per-platform skill markdown merge snippets.

No blocking issues surfaced. 12 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1959 functions depend on the 1268 functions this change touches.

Health — this change adds coupling hotspots:

  • new: deduplicate_entities() — 63 callers, 21 callees
  • new: build_merge() — 48 callers, 14 callees
  • new: extract_files_direct() — 17 callers, 20 callees
  • new: extract_corpus_parallel() — 26 callers, 12 callees
  • new: _call_claude_cli() — 31 callers, 9 callees
  • new: dispatch_command() — 2 callers, 123 callees
  • new: _extract_with_adaptive_retry() — 22 callers, 10 callees
  • new: _call_llm() — 11 callers, 18 callees
  • …and 23 more — each is listed as a finding

Verification — 1959 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: 1848 function(s) in the blast radius were not formally verified this run

Formal verification

Could not verify: Could not verify dispatch\_command.

The verifier did not have enough to check dispatch\_command, 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: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

Could not verify: Could not verify extract\_corpus\_parallel.

The verifier did not have enough to check extract\_corpus\_parallel, 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 `root` is annotated `Path` — outside the synthesizable primitive/collection set

· 31 more finding(s) on lines outside this diff (see the check run).

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.

Skill Part C never stamps _origin, so graphify update deletes the semantic layer of any doc without section numbers

2 participants