Skip to content

fix(discover): count promoted_from as a citation so hydration skips promoted sources - #190

Merged
kendrick merged 3 commits into
mainfrom
issue-178
Nov 10, 2026
Merged

kendrick merged 3 commits into
mainfrom
issue-178

Conversation

@kendrick

Copy link
Copy Markdown
Owner

ltm discover now counts a Record's promoted_from as a citation of the Hydration source it names. ltm promote writes only promoted_from, never source_refs, so a promoted ADR or decision log used to show an empty cited_by, and the hydrate skill drafted the same decision again as a second Proposal.

Closes #178

What Changed

Start with citedBy in src/core/discover.ts. It takes an optional fifth argument, repoRef, in the form <org>/<repo>:<repo-relative path>. A Record cites the source when its promoted_from equals repoRef or starts with repoRef#, so a decision-log entry's anchor doesn't matter. discover builds repoRef from repoIdentity(root).remote, the same ${org}/${repo} string src/cli/promote.ts writes, and caches it per repo root. A repo with no origin gets no repoRef, so only source_refs can cite there. Existing four-argument callers compile unchanged.

skills/hydrate/SKILL.md gets the same rule for agents working without ltm: the manual grep now matches promoted_from lines as well as source_refs.

The tests in test/core/discover.test.ts and test/cli/discover.test.ts cover an ADR and a decision-log entry cited through promoted_from, the falsifier from the issue (another repo's slug leaves cited_by empty, a different anchor keeps it cited), and a Consumer repo with no origin.

Verification

A reproducer agent that never saw the implementer's reasoning re-ran each claim against the branch. caller means it drove ltm discover through src/cli/bin.ts, and seam means it ran the check directly because no production caller applies.

  • The new tests fail on the old discover.ts and pass with the change (caller). It swapped the base discover.ts into a scratch copy and ran bun test test/core/discover.test.ts test/cli/discover.test.ts. Both new promoted_from tests failed there, and all 62 pass in the real tree. Through the CLI, with a Record that ltm promote --dry-run produced, discover . --json --bank $W/bank printed {"path":"docs/adr/0003-use-postgres.md","cited_by":["zmGosBfXC6"]}. Changing the slug to acme/billing printed "cited_by":[].
  • Typecheck and the full suite pass (seam, a suite-level claim): bun run typecheck && bun test gave 1742 pass, 3 skip, 0 fail over 1745 tests on this HEAD, rebased on main at 7cd6c4b.
  • The hydrate grep matches promoted_from (caller, an agent running the shell line): grep -rlE '^(source_refs|promoted_from): .*0003-use-postgres.md' _memory found the promoted Record, the #slug form, and the plain form, and skipped a related:-only line.
  • The skill diff touches only those two lines (seam, prose with no caller): git diff --stat shows skills/hydrate/SKILL.md | 4 ++--.
  • A symlinked path to the repo still cites (caller): from /tmp/ltm-sym.xe5p/link/svc, discover . --json --bank printed "cited_by":["zmGosBfXC6"], as it did for four other symlinked and absolute arguments.
  • No origin means no citation (caller): after git remote remove origin, discover . --json --bank ../bank printed "cited_by":[] for the ADR, and adding origin back cited it. The CLI test promoted_from does not cite when the Consumer repo has no origin to name it fails when the test sets origin instead of removing it.

Plan Concerns

The plan said to fill the slug cache from repoIdentity(root).remote whenever a Bank is given. repoRootOf can return a null root, and repoIdentity returns a null remote when .git exists but git can't resolve one. The cache keys on non-null roots only and stores a null remote as null, so those sources fall back to source_refs alone.

Left Out

…romoted sources

`ltm promote` records a Proposal's origin in `promoted_from` and never writes `source_refs`. So `ltm discover` kept listing a promoted ADR or decision log with an empty `cited_by`, and hydration drafted it again. `citedBy` now also cites a Record whose `promoted_from` is the source's `<org>/<repo>:<path>`, with or without a `#` anchor after it. One promoted decision-log entry therefore covers the whole log, as a `source_refs` hit does today. `discover` gets the `<org>/<repo>` half from `repoIdentity`, the parser `ltm promote` writes it with, once per repo root and only when a Bank is loaded. A bare prefix match would let `0003-use-postgres.md.bak` cite `0003-use-postgres.md`, so the anchor must start with `#`. Refs #178.
The skill gives a manual route for every `ltm` step, and its grep for citing Records read only `source_refs`, so a team without `ltm` would still redraft a promoted source. Refs #178.
With no origin remote, `discover` can't build the `<org>/<repo>` half of a `promoted_from` ref, so it must leave `cited_by` empty. The existing CLI tests run inside this repo, which has an origin, so only the core `citedBy` test covered that path. The new test removes the origin from a Consumer repo and checks the JSON `discover` prints. Refs #178.
@kendrick

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-10T21:56:27.098962Z 7d3eab3 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 7d3eab3bd3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@kendrick

kendrick commented Nov 10, 2026 •

Copy link
Copy Markdown
Owner Author

Deferred findings

One plan concern from the build. The build already handles it, so nothing is owed in this PR.

# Source Finding Outside because Recommendation Status
1 worker The plan said to fill the slug cache from repoIdentity(root).remote whenever a Bank is given, but repoRootOf can return a null root and repoIdentity returns a null remote when git can't resolve one; the build caches only non-null roots and stores a null remote as null, so those sources fall back to source_refs. plan concern, handled in the build; no follow-up code owed none: recorded for the reviewer; file only if a null-remote repo should cite through promoted_from dismissed: recorded for the reviewer; no code owed

@kendrick
kendrick merged commit 1039beb into main Nov 10, 2026
16 checks passed
@kendrick
kendrick deleted the issue-178 branch November 10, 2026 21:59
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.

ltm discover: a promoted ADR or decision log stays uncited, so hydration drafts it again

1 participant