Repository navigation
Conversation
…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.
|
@codex review |
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Deferred findingsOne plan concern from the build. The build already handles it, so nothing is owed in this PR.
|
ltm discovernow counts a Record'spromoted_fromas a citation of the Hydration source it names.ltm promotewrites onlypromoted_from, neversource_refs, so a promoted ADR or decision log used to show an emptycited_by, and the hydrate skill drafted the same decision again as a second Proposal.Closes #178
What Changed
Start with
citedByinsrc/core/discover.ts. It takes an optional fifth argument,repoRef, in the form<org>/<repo>:<repo-relative path>. A Record cites the source when itspromoted_fromequalsrepoRefor starts withrepoRef#, so a decision-log entry's anchor doesn't matter.discoverbuildsrepoReffromrepoIdentity(root).remote, the same${org}/${repo}stringsrc/cli/promote.tswrites, and caches it per repo root. A repo with no origin gets norepoRef, so onlysource_refscan cite there. Existing four-argument callers compile unchanged.skills/hydrate/SKILL.mdgets the same rule for agents working withoutltm: the manual grep now matchespromoted_fromlines as well assource_refs.The tests in
test/core/discover.test.tsandtest/cli/discover.test.tscover an ADR and a decision-log entry cited throughpromoted_from, the falsifier from the issue (another repo's slug leavescited_byempty, 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.
callermeans it droveltm discoverthroughsrc/cli/bin.ts, andseammeans it ran the check directly because no production caller applies.discover.tsand pass with the change (caller). It swapped the basediscover.tsinto a scratch copy and ranbun test test/core/discover.test.ts test/cli/discover.test.ts. Both newpromoted_fromtests failed there, and all 62 pass in the real tree. Through the CLI, with a Record thatltm promote --dry-runproduced,discover . --json --bank $W/bankprinted{"path":"docs/adr/0003-use-postgres.md","cited_by":["zmGosBfXC6"]}. Changing the slug toacme/billingprinted"cited_by":[].seam, a suite-level claim):bun run typecheck && bun testgave1742 pass, 3 skip, 0 failover 1745 tests on this HEAD, rebased onmainat 7cd6c4b.promoted_from(caller, an agent running the shell line):grep -rlE '^(source_refs|promoted_from): .*0003-use-postgres.md' _memoryfound the promoted Record, the#slugform, and the plain form, and skipped arelated:-only line.seam, prose with no caller):git diff --statshowsskills/hydrate/SKILL.md | 4 ++--.caller): from/tmp/ltm-sym.xe5p/link/svc,discover . --json --bankprinted"cited_by":["zmGosBfXC6"], as it did for four other symlinked and absolute arguments.caller): aftergit remote remove origin,discover . --json --bank ../bankprinted"cited_by":[]for the ADR, and adding origin back cited it. The CLI testpromoted_from does not cite when the Consumer repo has no origin to name itfails when the test sets origin instead of removing it.Plan Concerns
The plan said to fill the slug cache from
repoIdentity(root).remotewhenever a Bank is given.repoRootOfcan return a null root, andrepoIdentityreturns a null remote when.gitexists 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 tosource_refsalone.Left Out
discoveris pointed at the symlinked path. Withdocs/adr2 -> ../decisions,discover docs/adr2/0003-use-postgres.mdreportscited_by: [], whilediscover .lists the real path as cited.ltm promoteresolves the real path, so the two disagree. This is outside ltm discover: a promoted ADR or decision log stays uncited, so hydration drafts it again #178.promoted_fromwith the same file path. Thesource_refsgrep it sits beside was already that loose.${org}/${repo}string.src/cli/promote.ts,src/cli/query.ts, andsrc/core/discover.tseach build it inline. Folding them together touches files ltm promote --entry: metadata lines under a decision-log heading leak into the Proposal, and a styled stamp allows a second promotion #176 is also changing in parallel.citedBykeeps positionalremoteRefandrepoRefarguments rather than one source-identity object, because the plan fixed the five-argument signature.