* test(#3738): antigravity global skills/agents must resolve under ~/.gemini/config Regression tests (RED first): --skills-root and gsd-tools query surfaces, install-plan dest dirs, and converter skills-path rewrite. * fix(#3738): antigravity global skills/agents install to ~/.gemini/config Antigravity's machine-local discovery scans ~/.gemini/config/{skills,agents}; the configHome (~/.gemini/antigravity) is deprecated for artifacts. Declare the ADR-1239 skills/agents 'home' override on the antigravity global layout — the same mechanism codex uses (.agents) — and divert ~/.claude/skills/ references in converted global content to ~/.gemini/config/skills/. configHome, settings, probe/migration semantics, and the local .agents layout are unchanged. * fix(#3738): retire deprecated configHome artifacts via installer migration 010 Next install converges an existing antigravity install: manifest-managed skills/gsd-*/ and agents/gsd-*.md under the configHome (a location AGY does not scan) are removed — modified files backed up first, unmanifested and non-gsd entries preserved — and now-empty containers retired. Global scope only; the local .agents surface is live. Docs + inventory updated. * fix(#3738): converter sync in bin/install.js, harness emit-root coverage, migration baseline - bin/install.js converter gains the same ~/.claude/skills → ~/.gemini/config/ rewrite as src (ADR-1508 dual copy must stay in sync). - Parity-manifest walk covers home-override emit roots (extraEmitRootsFor) so antigravity's emitted skills/agents stay differential-visible at their new install root; install-tree fixture regen confirms an unchanged key set. - skills-from-commands rule declares the antigravity converter as a runtime-scoped transform; one ack fragment covers the identity-classed workflow whose antigravity copy embeds the old skills path. - Migration 010 checksum baseline + home-override set doc updated; existing tests updated to the #3738 contract (global dest, golden parity via layout dest, integration expectations). * fix(#3738): tolerate an absent extra emit root on baseline-side measurement The base tree's installer predates the home override, so <HOME>/.gemini/config does not exist there; walk() threw ENOENT and the in-job baseline build failed. An absent extra root is the legitimate pre-override shape — skip it. * fix(#3738): review findings — manifest agents root, bare skills-path rewrite, guard comment - writeManifest resolves the agents-kind home override (_kindDestDirSafe), so the manifest records agents at their actual install root and drift detection keeps working (isolated review finding 1, major). - Converter bare forms ~/.claude/skills and $HOME/.claude/skills (no trailing slash) divert to ~/.gemini/config/skills instead of falling through to the retired configHome path (finding 2). - real-home-guard comment updated: antigravity's global agents kind is the first agents-kind home override (finding 3, doc-only). - Regression tests for both behavioral findings. * chore(#3738): changeset fragment (pr number backfilled after PR creation) * chore(#3738): backfill changeset PR number (3921) * fix(#3738): sandbox HOME in tests that install antigravity global artifacts antigravity is the first home-override runtime in the golden-parity and skills-wrapper suites (codex is not in their runtime lists), so those tests never needed HOME sandboxing — the real-home guard now (correctly) refuses their un-sandboxed global installs on CI, where HOME is the passwd home. * fix(#3738): stop the K3 sequential-sandbox env leak; sandbox L2's home-override plans K3's two back-to-back sandboxHome calls leave HOME pointing at the first sandbox once the after-hooks restore (each call saves the env as it found it, so the second saves the first's sandbox as 'original'). On the windows matrix that leaked gsd-k3-qwen-* home into the L2 property, whose antigravity/global run then (correctly) refused via the #3712 real-home guard — antigravity is the runtime that made L2's plan escape into os.homedir(). K3 now manages the env with a single restore; L2 sandboxes HOME per run, mirroring L1. * fix(#3738): L2 property's HOME sandbox must exist on disk The #3712 guard's sandbox exemption fails closed when identify(effectiveHome) is 'absent' — L2 never created its configDir, so on the windows matrix (tmpdir under the real home) the antigravity/global run refused even with HOME sandboxed. Create the per-run sandbox dir and clean it up. --------- Co-authored-by: sim <sim@local>
tests/emitted-drift-acks/
Per-PR acknowledgment fragments for the differential attribution check
(tests/emitted-attribution.test.cjs, ADR-2719 / #2789 / #2914).
This directory being empty is the healthy steady state. A fragment appearing
in a diff is the alarm; a fragment sitting here on next is spent cruft.
README.md is not a fragment — every reader filters on .json — and exists so
the directory (which CONTEXT.md and CONTRIBUTING.md both reference by path)
survives the sweep that empties it.
The lifecycle, in three steps
-
The gate names its own remedy. When an emitted-artifact hash moves, or a
gsd-core/workflows/*.md/agents/gsd-*.mdfile grows, and your diff cannot explain it, the failure output tells you which key to use and prints a minimal valid document to paste. Create a NEW fragment named for your issue or PR (<NNNN>-<slug>.json) — never reuse someone else's, and never revive the legacy singletests/emitted-drift-ack.json. -
Note the two key spaces. The message says which one applies. An unattributable hash ripple is keyed on the emitted path (
skills/gsd-add-tests/SKILL.md); growth is keyed on the bare filename as it appears undergsd-core/workflows/oragents/(explore.md). -
The fragment is deleted once it has merged (#3078). Every entry is scoped to the diff that introduced it, so the moment it lands on
nextits prose is already at the base — it is spent and can no longer clear anything, while still owning its path keys. Theguard-no-ack-on-nextjob redsnextand prints the exactgit rmfor every fully-spent fragment.You no longer have to run that
git rmyourself (#3875). Theack-fragment-sweepworkflow runs every six hours, asks the guard for its own sweep list (--sweep-plan), and opens a PR deleting exactly what the guard named. Deleting the fragment in a follow-up PR by hand still works and is still welcome — it is simply no longer the only thing standing between a merged fragment and a rednext.The sweep is automated because the manual remedy could not keep up. The guard evaluates at MERGE time; a hand-authored
git rmis fixed at BRANCH time, so any ack-carrying PR that merges in between invalidates it. #3823 lost exactly that race to #3809 on its own merge commit and leftnextred for 24 consecutive pushes.
Why the sweep exists
Fragments end the file conflict the single shared document caused. They do not end the key conflict: two ack sources may never name the same path, and that is a hard, loudly-reported error. So a fully-spent fragment left here walls off every path it owns — the next PR to grow one of them can declare it neither in the owning fragment (spent, gates nothing) nor in its own (duplicate). #2914 assumed a persisting fragment was harmless; #3078 measured the cost at 45 fragments owning 403 paths and made the guard sweep them.
A partially spent fragment is deliberately left alone. That asymmetry is what keeps the re-arm route working: appending prose to a live entry re-arms it, and re-arming deliberately costs an actual new sentence — the comparison strips zero-width characters and collapses whitespace precisely so a zero-information edit cannot fake one.
Never pin a fragment in a test
A fragment is deleted the moment it has merged (see step 3 above), so any test
that asserts one exists, or asserts its contents, will fail the instant
guard-no-ack-on-next sweeps it — and that failure has nothing to do with the
behavior the fragment once explained. This has already cost two suites:
tests/emitted-attribution.test.cjs's three #2914 migration pins, and
tests/agent-tracked-source-rule.test.cjs's #3645 growth-ack pin. What a test
may legitimately assert is the BEHAVIOR the ack explains, or the guard's own
verdict (assertNoAllSpentFragments, assertAbsentOnNext) — never the
paperwork.
Do not regenerate anything
There is no baseline file to re-run a generator over; #2724 deleted it. If you find yourself hunting for one, that is the predictable wrong guess.
See CONTRIBUTING.md → "Editing shipped content", docs/TESTING-SUITES.md, and
CONTEXT.md's RULESET.EMITTED_ATTRIBUTION for the full model.