Skip to content

fix(sem-annotate): anchor predating the entity is classified fresh (sem diff 'added' ignored); v2.4.3 orphaned check misdiagnosed sem#479 #39

Description

@ericfitz

Summary

sem-annotate's staleness check silently classifies a marker as fresh when its SEM@<sha> anchor predates the entity's introducing commit. sem diff <anchor>..HEAD -- <file> correctly reports such an entity as added (relative to that base the entity is new), but _parse_changed_entities only counts changeType == "modified", so no later body change against that anchor is ever detected. This is the actual cause of the tmi DeduplicateGroups incident written up in #30; the squash-merge/orphaned-anchor diagnosis there (and filed upstream as Ataraxy-Labs/sem#479, closed cannot-reproduce) was wrong, and the v2.4.3 reachability workaround (#34) does not cover this case while re-describing far more than it needs to.

Steps to Reproduce

Linear history, no squash-merge, anchor fully reachable:

git init -qb main && printf 'def other():\n    return 0\n' > o.py && git add . && git commit -qm base
H=$(git rev-parse --short=8 HEAD)
# new file + new entity, marker anchored at then-HEAD (the parent), all in ONE commit
printf "# SEM@$H: increment input by one\ndef alpha(x):\n    return x + 1\n" > m.py
git add . && git commit -qm "add alpha"
printf "# SEM@$H: increment input by one\ndef alpha(x):\n    return x + 99\n" > m.py
git commit -qam "change alpha body"
git merge-base --is-ancestor $H HEAD; echo $?          # 0 -- reachable
sem diff --json $H..HEAD --no-cosmetics -- m.py         # alpha: changeType "added", modified: 0
python dev/scripts/sem_annotate.py scan m.py            # []

Expected Behavior

alpha is reported stale (its body changed after the marker was written; the anchor cannot vouch for it).

Actual Behavior

scan returns [] — on v2.4.2 and v2.4.3 alike. No warning, no status.

Evidence

Replayed the real tmi state at f89431d5 (2026-08-09, the batch-end refresh where #30 was observed) in a detached worktree:

  • DeduplicateGroups carried SEM@91a78cdd…. git cat-file -e 91a78cdd:internal/dbschema/group_dedupe.gopath exists on disk, but not in '91a78cdd'. The file was created in db8c2159, whose parent is 91a78cdd; the marker was hand-written in that same commit, anchored at then-HEAD. The SEM@db8c2159 anchors mentioned in sem: SEM@sha staleness detection silently no-ops when the anchor commit is orphaned by squash-merge #30 follow the identical pattern (parent of the introducing commit 55071995).
  • sem diff --json 91a78cdd..HEAD --no-cosmetics -- internal/dbschema/group_dedupe.gosummary: added 29, modified 0; every entity including DeduplicateGroups is added.
  • sem log DeduplicateGroups correctly shows added @ 8dfef8f6, modified (logic) @ bb408815 — sem's history is right; only our diff parser drops the added case.

Squash-merge orphaning is not a factor: with sem 0.21.0, sem diff <orphaned-branch-sha>..HEAD reports the modification correctly (JSON and human output, exit 0), and the pre-fix v2.4.2 scan classifies that case stale. This matches the maintainer's finding on sem#479 (they could not reproduce on 0.21.0 or 0.22.1; unresolvable bases error loudly with exit 1).

Possible Cause

dev/scripts/sem_annotate.py::_parse_changed_entities filters changeType == "modified" only. An entity reported added since its anchor means the anchor never described this body — indistinguishable from "added and later modified" — so it must be treated as a logic change, not ignored.

Secondary: sha_reachable() / the orphaned status added in v2.4.3 keys on a condition that does not cause the failure. In a squash-merge repo every marker written on a branch has an unreachable anchor once merged, so after each release the next scan re-describes essentially the whole annotated codebase (verified: an untouched sibling entity is flagged orphaned alongside the changed one).

Impact

  • Silent staleness for any marker whose anchor predates the entity — the common outcome whenever a marker is hand-written at HEAD before the entity's commit exists (the sem-auto convention invites exactly this).
  • v2.4.3 turns every post-squash scan into a full LLM re-describe with no correctness gain.
  • docs/upstream/sem-orphaned-anchor-staleness.md records a diagnosis now known to be wrong.

Proposed fix

  1. Treat added (as well as modified) for the entity in the --no-cosmetics diff as a logic change → stale.
  2. Remove the reachability check and the orphaned status; restore the previous invalid-sha wording for unresolvable anchors (sem errors loudly there, which we already catch).
  3. Replace the upstream draft with a retraction note pointing at sem#479's closure and this issue.
  4. Bump the dev plugin to 2.4.4.

Environment

sem-cli 0.21.0 (Homebrew), macOS 25.6.0; dev plugin 2.4.3.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions