Description
These gaps exist on main (origin/main at 5e5b86d9) and are outside the worktree fixes. Two lose work, and three can make a push revert a teammate's update. They come from reading the code and the PR reviews (#813, #814, #819). Item 1 has been reproduced with the CLI (#825); the rest come from reading the code. Anything that only exists in an open PR's branch is fixed in that PR, not tracked here.
where teamai decides "did the member edit this copy?"
├── learnings-wt/ import --from-mr writes here ── 1. never committed (fixed: #825, merged)
├── pre-push sync (git show) single-repo mode ── 2. path never resolves
├── push base
│ ├── per checkout rules, skills ── fixed by #819 (merged)
│ ├── agents still the shared lastPullRev ── 3.
│ ├── user scope no per-checkout record ── 4.
│ └── skill copy fails partway ── 5.
Loses or reverts work
| # |
What happens |
Where |
| 1 |
import --from-mr writes the learning into learnings-wt, but autoPushViaMR commits . in repo.localPath, which is another checkout. It gets "nothing to commit", so the learning is recallable here and never reaches the team. The SessionStart MR hint sends members to this command. |
main: src/import.ts:302, src/utils/git.ts:417, src/utils/learnings-roots.ts:64 |
| 2 |
In single-repo mode the pre-push sync never matches. Push runs with repo.localPath = <knowledge-wt>/.teamai, and the sync passes rules/x.md to git show <rev>:<path>, which git resolves from the repo root (fatal: path '.teamai/rules/x.md' exists, but not 'rules/x.md'). Every teammate update then reads as a local edit. getFileContentWhenAdded already prefixes ./. Fixed in #827 (merged). |
main: src/utils/pre-push-sync.ts:122, :227, :244, src/utils/reports-branch.ts:161, src/utils/git.ts:943 |
| 3 |
Agents placed with --role/--project compare with the shared lastPullRev, not with this checkout's bases. This is the #812 revert for agents. Fixed in #827 (merged). |
main: src/resources/agents.ts:177, :417 |
| 4 |
User scope never records a push base. HOME's copy synced to R2 is compared with R1 after a teammate's R3 and offered over it. |
main: src/push.ts:974; #819: src/push.ts:976 (project scope only) |
| 5 |
If the skill copy in the pre-push sync fails partway, the mix of R1 and R2 files matches no base and the skill reads as modified. Fix: copy to a sibling temp dir, then rename. Fixed in #827 (merged). |
main: src/utils/pre-push-sync.ts:259; #819: :237 |
push, then a teammate's update, before any pull
- base = lastPullRev (R1) -> local R2 != R1 -> "edited" -> offered over R3
+ base = rev push synced -> local R2 == R2 -> updated to R3 (#819: project scope, rules + skills)
Also on main, found while fixing item 1
| # |
What happens |
Where |
| 6 |
import --from-mr writes the learning at the shared root, not in the project's namespace as contribute does. Fixed in #825 (merged). |
src/contribute.ts:170 |
| 9 |
import --from-mr checks whether a new learning supersedes an existing one, but reads only the top level of each learnings directory, so learnings inside a project namespace are never compared. The result is never saved either, so its "marking as superseded" warning is false. contribute has no such check. |
src/utils/dedup.ts:97, src/import-mr.ts:222-246 |
| 10 |
Single-repo mode, with the member's branch behind main: the active tree's .teamai/rules and .teamai/skills are themselves push scan sources, so their stale copy of a rule or skill a teammate updated on main is listed as modified, even after the pre-push sync fixes .claude/rules. |
src/resources/rules.ts:132 (guard only for placed rules), src/resources/skills.ts:458 (no guard) |
| 7 |
Learnings that 0.22's import --from-mr left untracked in learnings-wt are never published or cleaned up. |
src/utils/branch-worktree.ts:330, :574 |
| 8 |
The bind-hint markers are machine-wide files in os.tmpdir(), shared by every user and never removed. Dropped: #829 was closed because the bind hint itself will be removed (comment). |
src/local-agent.ts:1117, :1192 |
| 11 |
Queue writes take no lock. A contribute or import --from-mr already running while a migration retires .teamai, or while init switches modes, can write after the queue was moved: the learning ends up in .teamai.bak, or loses the config that says which install queued it. Found in #814's review. Being fixed in #814: queue writes, the migration and init share one lock. Fixed in #814 (merged). |
src/utils/pending-learnings.ts (savePendingLearning), src/migrate.ts, src/init.ts |
| 12 |
recall's index rebuild throws in deliveredIndexSources when roles.yaml or projects.yaml can't be read, and builds no index, so recall finds nothing until the team config is fixed. A skills collision no longer throws since #816, but with no previous index it indexes 0 skills without a warning. |
src/recall.ts:341-355 |
| 13 |
A queue's owner is recorded only by its kind. Re-running init in git mode against another team repo keeps the old team's queue, and the next pull publishes it to the new one. Fixed in #814 (merged). |
src/utils/pending-learnings.ts, src/init.ts |
| 14 |
config.yaml is written in place, not atomically. A command reading it at that moment fails; a concurrent contribute fails closed (exit 1, nothing lost). Fixed in #831 (merged). |
src/config.ts:253 |
| 15 |
After a refresh fails, the reports readers still call ensure without the lock, so they can race a writer that holds it. |
src/utils/reports-branch.ts:102 |
| 16 |
viz in user scope builds its fallback index from [getUserLearningsDir(), ...learningsRoots().read] instead of indexableLearningsRoots, so a learnings checkout of another repository is not left out; and in both scopes it passes no learningsNamespaces, so project-namespaced learnings are missing from the dashboard. |
src/viz.ts (resolveVizRoot, loadEntries) |
| 17 |
If init fails between re-cloning the team repo and saving the new config (for example the queue lock is busy), the old team's config.yaml is left beside the new team's clone. |
src/init.ts (clone, then save) |
| 18 |
teamai import --from-mr runs inside a listr2 task list, which in a TTY can hide its Accept learning? [Y/n] prompt. Found while fixing item 9 (#834). |
src/import.ts |
| 19 |
A project pull that inherits user scope (inheritUserScope) updates the HOME copies but not the user-scope push bases, so the next user-scope push can compare them with an older base. Found while fixing item 4. |
src/pull.ts (inheritUserScope) |
| 20 |
pull --dry-run still publishes the queued learnings (from reading the code). |
src/pull.ts (publish before the dry-run returns) |
| 21 |
In single-repo mode the duplicate check for leftover learnings reads the old .teamai/learnings-wt checkout, which may be stale. Found in #838. |
src/utils/learnings-publish.ts |
Cleanup (fixed in #825, merged)
- A main checkout opened through a symlink with another name gets that name as its wiki slug, while its worktrees get the real one (
src/codebase-extract.ts:548).
- A remote-form key and a colliding local path can share a label and merge in
stats --by-repo (src/utils/repo-attribution.ts:139-145).
local-agent.test.ts "emits hint only once per sessionId" is flaky: its marker is a shared file in os.tmpdir() keyed by a fixed session id (src/local-agent.ts:1192).
Proposed order
Done:
In open PRs:
In progress, three PRs by area (started after #814 merged):
| PR |
Items |
Why together |
| Push (#835) |
4, 10, 19 |
Both decide whether a copy is a local edit or a teammate's update on push; same e2e harness as #827. |
| Learnings lookup (#834) |
9, 12, 16, 18 |
Both decide which learnings are found (the duplicate check and the recall index). |
| Data layout (#838) |
7, 15, 17, 20, 21, and #814's follow-ups |
Cleanup of the layout #814 introduces: drop the now-redundant checkout-queue drain, reword retire-only's "Finished an interrupted migration" for linked worktrees, and ignore the temp file an interrupted config save can leave in a legacy in-repo .teamai (#831). |
Items 4, 7 and 12 are decided, so these start as soon as #814 merges. Items 15 and 17 are in #838. Every open item is now in an open PR: 16 and 18 in #834, 19 in #835, 20 and 21 in #838.
Reproduction (not run)
Item 1 was reproduced with the real CLI in #825: the output says "✔ Push changes via MR", but the learning stays untracked in learnings-wt and the team repo gets no teamai-learnings branch.
Item 2:
- A single-repo project where a teammate updates
.teamai/rules/x.md after your pull.
teamai --dry-run push: x is listed as modified although you never edited it.
Environment
- OS: macOS (Darwin 25.5.0)
- teamai: 0.22.0 (
origin/main 5e5b86d9)
- Provider: GitHub
- AI tool(s): Claude Code
Related: #807, #808, #809, #812, #813, #814, #819.
Description
These gaps exist on
main(origin/mainat5e5b86d9) and are outside the worktree fixes. Two lose work, and three can make a push revert a teammate's update. They come from reading the code and the PR reviews (#813, #814, #819). Item 1 has been reproduced with the CLI (#825); the rest come from reading the code. Anything that only exists in an open PR's branch is fixed in that PR, not tracked here.Loses or reverts work
import --from-mrwrites the learning intolearnings-wt, butautoPushViaMRcommits.inrepo.localPath, which is another checkout. It gets "nothing to commit", so the learning is recallable here and never reaches the team. The SessionStart MR hint sends members to this command.src/import.ts:302,src/utils/git.ts:417,src/utils/learnings-roots.ts:64In single-repo mode the pre-push sync never matches. Push runs withFixed in #827 (merged).repo.localPath = <knowledge-wt>/.teamai, and the sync passesrules/x.mdtogit show <rev>:<path>, which git resolves from the repo root (fatal: path '.teamai/rules/x.md' exists, but not 'rules/x.md'). Every teammate update then reads as a local edit.getFileContentWhenAddedalready prefixes./.src/utils/pre-push-sync.ts:122,:227,:244,src/utils/reports-branch.ts:161,src/utils/git.ts:943Agents placed withFixed in #827 (merged).--role/--projectcompare with the sharedlastPullRev, not with this checkout's bases. This is the #812 revert for agents.src/resources/agents.ts:177,:417src/push.ts:974; #819:src/push.ts:976(project scope only)If the skill copy in the pre-push sync fails partway, the mix of R1 and R2 files matches no base and the skill reads as modified. Fix: copy to a sibling temp dir, then rename.Fixed in #827 (merged).src/utils/pre-push-sync.ts:259; #819::237Also on
main, found while fixing item 1Fixed in #825 (merged).import --from-mrwrites the learning at the shared root, not in the project's namespace ascontributedoes.src/contribute.ts:170import --from-mrchecks whether a new learning supersedes an existing one, but reads only the top level of each learnings directory, so learnings inside a project namespace are never compared. The result is never saved either, so its "marking as superseded" warning is false.contributehas no such check.src/utils/dedup.ts:97,src/import-mr.ts:222-246main: the active tree's.teamai/rulesand.teamai/skillsare themselves push scan sources, so their stale copy of a rule or skill a teammate updated onmainis listed as modified, even after the pre-push sync fixes.claude/rules.src/resources/rules.ts:132(guard only for placed rules),src/resources/skills.ts:458(no guard)import --from-mrleft untracked inlearnings-wtare never published or cleaned up.src/utils/branch-worktree.ts:330,:574The bind-hint markers are machine-wide files inDropped: #829 was closed because the bind hint itself will be removed (comment).os.tmpdir(), shared by every user and never removed.src/local-agent.ts:1117,:1192Queue writes take no lock. AFixed in #814 (merged).contributeorimport --from-mralready running while a migration retires.teamai, or whileinitswitches modes, can write after the queue was moved: the learning ends up in.teamai.bak, or loses the config that says which install queued it. Found in #814's review. Being fixed in #814: queue writes, the migration andinitshare one lock.src/utils/pending-learnings.ts(savePendingLearning),src/migrate.ts,src/init.tsrecall's index rebuild throws indeliveredIndexSourceswhenroles.yamlorprojects.yamlcan't be read, and builds no index, so recall finds nothing until the team config is fixed. A skills collision no longer throws since #816, but with no previous index it indexes 0 skills without a warning.src/recall.ts:341-355A queue's owner is recorded only by its kind. Re-runningFixed in #814 (merged).initin git mode against another team repo keeps the old team's queue, and the next pull publishes it to the new one.src/utils/pending-learnings.ts,src/init.tsFixed in #831 (merged).config.yamlis written in place, not atomically. A command reading it at that moment fails; a concurrentcontributefails closed (exit 1, nothing lost).src/config.ts:253ensurewithout the lock, so they can race a writer that holds it.src/utils/reports-branch.ts:102vizin user scope builds its fallback index from[getUserLearningsDir(), ...learningsRoots().read]instead ofindexableLearningsRoots, so a learnings checkout of another repository is not left out; and in both scopes it passes nolearningsNamespaces, so project-namespaced learnings are missing from the dashboard.src/viz.ts(resolveVizRoot,loadEntries)initfails between re-cloning the team repo and saving the new config (for example the queue lock is busy), the old team'sconfig.yamlis left beside the new team's clone.src/init.ts(clone, then save)teamai import --from-mrruns inside a listr2 task list, which in a TTY can hide itsAccept learning? [Y/n]prompt. Found while fixing item 9 (#834).src/import.tsinheritUserScope) updates the HOME copies but not the user-scope push bases, so the next user-scope push can compare them with an older base. Found while fixing item 4.src/pull.ts(inheritUserScope)pull --dry-runstill publishes the queued learnings (from reading the code).src/pull.ts(publish before the dry-run returns).teamai/learnings-wtcheckout, which may be stale. Found in #838.src/utils/learnings-publish.tsCleanup (fixed in #825, merged)
src/codebase-extract.ts:548).stats --by-repo(src/utils/repo-attribution.ts:139-145).local-agent.test.ts"emits hint only once per sessionId" is flaky: its marker is a shared file inos.tmpdir()keyed by a fixed session id (src/local-agent.ts:1192).Proposed order
Done:
import --from-mrextracts (#823) #825 (merged): items 1 and 6, and the Cleanup items.In open PRs:
In progress, three PRs by area (started after #814 merged):
.teamai(#831).Items 4, 7 and 12 are decided, so these start as soon as #814 merges. Items 15 and 17 are in #838. Every open item is now in an open PR: 16 and 18 in #834, 19 in #835, 20 and 21 in #838.
Reproduction (not run)
Item 1 was reproduced with the real CLI in #825: the output says "✔ Push changes via MR", but the learning stays untracked in
learnings-wtand the team repo gets noteamai-learningsbranch.Item 2:
.teamai/rules/x.mdafter your pull.teamai --dry-run push:xis listed as modified although you never edited it.Environment
origin/main5e5b86d9)Related: #807, #808, #809, #812, #813, #814, #819.