From 6e6acabfc0a9adde2429019f42940f64829e099e Mon Sep 17 00:00:00 2001 From: Thierry Kwiatkowski Date: Mon, 5 Oct 2026 23:59:46 +0200 Subject: [PATCH 1/2] test(cli): prove sync restores only what antigravity setup wrote sync --force restores a drifted AIDD skill and leaves a user skill and a user named hook in .agents/hooks.json as they were. The clean case moves into the same file, renamed for both. Refs #511 Co-Authored-By: Claude Opus 5.5 --- .../e2e/antigravity-foreign-files.e2e.test.ts | 98 +++++++++++++++++++ ...clean-antigravity-foreign-file.e2e.test.ts | 48 --------- 2 files changed, 98 insertions(+), 48 deletions(-) create mode 100644 cli/tests/e2e/antigravity-foreign-files.e2e.test.ts delete mode 100644 cli/tests/e2e/clean-antigravity-foreign-file.e2e.test.ts diff --git a/cli/tests/e2e/antigravity-foreign-files.e2e.test.ts b/cli/tests/e2e/antigravity-foreign-files.e2e.test.ts new file mode 100644 index 000000000..cc68cdc97 --- /dev/null +++ b/cli/tests/e2e/antigravity-foreign-files.e2e.test.ts @@ -0,0 +1,98 @@ +import { existsSync } from "node:fs"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; +import { join, resolve } from "node:path"; +import { describe, expect, it } from "vitest"; +import { createTestEnv, runCli } from "./helpers.js"; + +const FRAMEWORK_REAL_PATH = resolve(process.cwd(), "tests/fixtures/framework-real"); +const OWN_SKILL = "aidd-vcs-01-commit/SKILL.md"; +const FOREIGN_SKILL = "# mine\n"; +const OWN_HOOKED_SKILL = "aidd-context-05-learn/SKILL.md"; +const FOREIGN_HOOK = { SessionStart: [{ type: "command", command: "echo lint" }] }; + +describe("E2E: antigravity under a .agents/ it does not own", () => { + it("clean removes the skills it wrote and leaves a user skill beside them", async () => { + const test = await createTestEnv("clean-antigravity-foreign"); + try { + const skills = join(test.projectDir, ".agents", "skills"); + const foreign = join(skills, "mine", "SKILL.md"); + await mkdir(join(skills, "mine"), { recursive: true }); + await writeFile(foreign, FOREIGN_SKILL); + + const setup = await runCli( + [ + "setup", + "--source", + "local", + "--path", + FRAMEWORK_REAL_PATH, + "--ai", + "antigravity", + "--plugins", + "aidd-vcs", + "--yes", + ], + test.projectDir, + test.fakeHome + ); + expect(setup.exitCode).toBe(0); + expect(existsSync(join(skills, OWN_SKILL))).toBe(true); + + const clean = await runCli(["clean", "--force"], test.projectDir, test.fakeHome); + + expect(clean.exitCode).toBe(0); + expect(existsSync(join(skills, OWN_SKILL))).toBe(false); + expect(await readFile(foreign, "utf-8")).toBe(FOREIGN_SKILL); + } finally { + await test.cleanup(); + } + }); + + it("sync --force restores a drifted skill it wrote and leaves a user skill and a user named hook as they were", async () => { + const test = await createTestEnv("sync-antigravity-foreign"); + try { + const skills = join(test.projectDir, ".agents", "skills"); + const hooksFile = join(test.projectDir, ".agents", "hooks.json"); + const foreign = join(skills, "mine", "SKILL.md"); + const own = join(skills, OWN_HOOKED_SKILL); + + const setup = await runCli( + [ + "setup", + "--source", + "local", + "--path", + FRAMEWORK_REAL_PATH, + "--ai", + "antigravity", + "--plugins", + "aidd-context", + "--yes", + ], + test.projectDir, + test.fakeHome + ); + expect(setup.exitCode).toBe(0); + const installed = await readFile(own, "utf-8"); + const hooks = JSON.parse(await readFile(hooksFile, "utf-8")); + expect(Object.keys(hooks)).toEqual(["aidd-context"]); + await writeFile(hooksFile, JSON.stringify({ ...hooks, lint: FOREIGN_HOOK }, null, 2)); + await mkdir(join(skills, "mine"), { recursive: true }); + await writeFile(foreign, FOREIGN_SKILL); + await writeFile(own, `${installed}drift\n`); + + const sync = await runCli(["sync", "--force"], test.projectDir, test.fakeHome); + + expect(sync.exitCode).toBe(0); + expect(await readFile(own, "utf-8")).toBe(installed); + expect(await readFile(foreign, "utf-8")).toBe(FOREIGN_SKILL); + const restored = JSON.parse(await readFile(hooksFile, "utf-8")); + expect(restored, "restore remerges its own key: order may move, content may not").toEqual({ + ...hooks, + lint: FOREIGN_HOOK, + }); + } finally { + await test.cleanup(); + } + }); +}); diff --git a/cli/tests/e2e/clean-antigravity-foreign-file.e2e.test.ts b/cli/tests/e2e/clean-antigravity-foreign-file.e2e.test.ts deleted file mode 100644 index 3f94b5576..000000000 --- a/cli/tests/e2e/clean-antigravity-foreign-file.e2e.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { existsSync } from "node:fs"; -import { mkdir, readFile, writeFile } from "node:fs/promises"; -import { join, resolve } from "node:path"; -import { describe, expect, it } from "vitest"; -import { createTestEnv, runCli } from "./helpers.js"; - -const FRAMEWORK_REAL_PATH = resolve(process.cwd(), "tests/fixtures/framework-real"); -const OWN_SKILL = "aidd-vcs-01-commit/SKILL.md"; -const FOREIGN_SKILL = "# mine\n"; - -describe("E2E: antigravity under a .agents/ it does not own", () => { - it("clean removes the skills it wrote and leaves a user skill beside them", async () => { - const test = await createTestEnv("clean-antigravity-foreign"); - try { - const skills = join(test.projectDir, ".agents", "skills"); - const foreign = join(skills, "mine", "SKILL.md"); - await mkdir(join(skills, "mine"), { recursive: true }); - await writeFile(foreign, FOREIGN_SKILL); - - const setup = await runCli( - [ - "setup", - "--source", - "local", - "--path", - FRAMEWORK_REAL_PATH, - "--ai", - "antigravity", - "--plugins", - "aidd-vcs", - "--yes", - ], - test.projectDir, - test.fakeHome - ); - expect(setup.exitCode).toBe(0); - expect(existsSync(join(skills, OWN_SKILL))).toBe(true); - - const clean = await runCli(["clean", "--force"], test.projectDir, test.fakeHome); - - expect(clean.exitCode).toBe(0); - expect(existsSync(join(skills, OWN_SKILL))).toBe(false); - expect(await readFile(foreign, "utf-8")).toBe(FOREIGN_SKILL); - } finally { - await test.cleanup(); - } - }); -}); From 5ea810390db54ab712eacab09258e5a5b882a02b Mon Sep 17 00:00:00 2001 From: Thierry Kwiatkowski Date: Wed, 14 Oct 2026 19:00:00 +0200 Subject: [PATCH 2/2] docs: plan the antigravity review fixes Co-Authored-By: Claude Opus 5.5 --- .../backlog-link.json | 5 + .../phase-1.md | 66 +++++++++++ .../phase-2.md | 108 ++++++++++++++++++ .../phase-3.md | 69 +++++++++++ .../phase-4.md | 82 +++++++++++++ .../phase-5.md | 73 ++++++++++++ .../plan.md | 32 ++++++ .../review.md | 40 +++++++ 8 files changed, 475 insertions(+) create mode 100644 aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/backlog-link.json create mode 100644 aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-1.md create mode 100644 aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-2.md create mode 100644 aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-3.md create mode 100644 aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-4.md create mode 100644 aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-5.md create mode 100644 aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/plan.md create mode 100644 aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/review.md diff --git a/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/backlog-link.json b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/backlog-link.json new file mode 100644 index 000000000..b148c76ed --- /dev/null +++ b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/backlog-link.json @@ -0,0 +1,5 @@ +{ + "backlog": "ai-driven-dev/framework#511", + "written_at": "2026-10-14T12:00:00Z", + "written_by": "aidd-dev:01-plan" +} diff --git a/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-1.md b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-1.md new file mode 100644 index 000000000..45933bade --- /dev/null +++ b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-1.md @@ -0,0 +1,66 @@ +--- +status: pending +--- + +# Instruction: Host profile: user-facing skip message, conformance guard + +Owning commit: `feat(cli): add Antigravity CLI as a flat host for skills` on `feat/511-antigravity-host`. + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +cli/ +├── src/contexts/tools/domain/profiles/antigravity/profile.ts ✏️ skip reason without a ticket reference +└── tests/contexts/tools/domain/ + ├── profiles/antigravity/profile.unit.test.ts ✏️ assert the new reason + └── registry-conformance.unit.test.ts ✏️ named opt-out replaces the silent early return +``` + +## User Journey + +```mermaid +flowchart TD + A[aidd setup --ai antigravity on a hooks plugin] --> B[skip reason printed] + B --> C[no ticket id in the message] +``` + +## Test Scope + +```mermaid +--- +title: Test scope +--- +journey + section Setup + Check out the host branch => profile and conformance tests present: 5: system + section Happy path + Read the antigravity hooks skip reason => it says hooks are not wired yet, with no ticket id: 5: system + Run the conformance suite => antigravity passes through its named opt-out: 5: system + section Edge case - new flat-only tool + A tool declaring plugins with no marketplace contract and no opt-out => conformance runs => the probe assertion fails: 1: system +``` + +## Tasks to do + +### `1)` Skip reason + +> The message a user reads carries no ticket reference. + +1. Set `hooksUnsupportedReason` to `Antigravity CLI hooks are not wired yet.` +2. Assert that exact string in the profile test instead of `toContain("phase 3")`. + +### `2)` Explicit conformance opt-out + +> A future flat-only tool cannot skip the marketplace-probe check by accident. + +1. Replace the early `return` with a named set of tools exempt from the marketplace probe, holding `antigravity` with a one-line reason. +2. Mutation check: drop `antigravity` from the set, the probe test goes red; restore. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| ---- | ------------------- | +| 1 | The antigravity hooks skip reason contains no `#` ticket id and the profile test pins it | +| 2 | Removing antigravity from the opt-out set fails the conformance test for antigravity only | diff --git a/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-2.md b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-2.md new file mode 100644 index 000000000..7dcd59330 --- /dev/null +++ b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-2.md @@ -0,0 +1,108 @@ +--- +status: pending +--- + +# Instruction: Project hooks: `--force` reaches the edit guard + +Owning commit: `feat(cli): merge plugin hooks into antigravity's .agents/hooks.json` on `feat/511-antigravity-memory-hook`. + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +cli/ +├── src/contexts/framework/application/ +│ ├── shared/remove-project-hooks.ts ✏️ overwriteEdited option; refusal hints --force +│ ├── framework/translator/project-hooks-materializer.ts ✏️ honour overwriteEdited, obsolete-script removal too +│ ├── framework/translator/plugin-translator.ts ✏️ contract carries overwriteEdited +│ ├── framework/translator/mode-b-flat-materialization-translator.ts ✏️ forward it +│ ├── framework/translator/built-tree-materialization-translator.ts ✏️ forward it; drop flat hook scripts from plugin files +│ ├── plugin/plugin-helpers.ts ✏️ materializeViaTranslator forwards it +│ ├── shared/apply-plugin-files-use-case.ts ✏️ option force +│ ├── restore/restore-all-plugins-use-case.ts ✏️ option force +│ ├── restore/restore-use-case.ts ✏️ pass ctx.force to plugin restore +│ └── clean-use-case.ts ✏️ pass options.force to hook preflight and removal +├── src/contexts/tools/domain/profiles/antigravity/antigravity-hooks.ts ✏️ comment without a pinned agy version +├── src/contexts/translate/application/strategies/flat-build-strategy.ts ✏️ unparsable hooks file named, left untouched +└── tests/ ✏️ reviewer reproductions, duplicate-record check, translate error +``` + +## User Journey + +```mermaid +flowchart TD + A[setup --ai antigravity] --> B[user edits AIDD hook script or its hooks.json entry] + B --> C{command} + C -- sync --force --> D[AIDD entry and script rewritten, user key kept, drifted skill restored] + C -- clean --force --> E[AIDD entry and scripts removed, user key kept, all plugin files removed] + C -- sync without --force --> F[refused, message suggests --force] +``` + +## Test Scope + +```mermaid +--- +title: Test scope +--- +journey + section Setup + Install aidd-context for antigravity in a temp project with a user lint hook => hooks.json holds lint and aidd-context, provenance recorded: 5: system + section Happy path + Edit the AIDD hook script then sync --force => script restored to installed content: 5: cli + Edit the AIDD hooks.json entry then sync --force => entry restored, lint untouched: 5: cli + Edit the AIDD hook then clean --force => AIDD entry and script gone, lint kept, plugin files gone: 5: cli + section Edge case - no force + Edited hook => sync without --force => refused with a hint to rerun with --force: 1: cli + section Edge case - ownership unproven + Hook script path outside the plugin hooks dir in provenance => sync --force => still refused: 1: cli + section Edge case - unparsable hooks file + Invalid .agents/hooks.json => translate --as flat => error names the file, file left untouched: 1: cli + section Teardown + Remove the temp project => baseline restored: 5: system +``` + +## Tasks to do + +### `1)` Reproduce first + +> The reviewer's three reproductions fail before any production change. + +1. Add use-case level tests for: edited script + `sync --force`, edited entry + `sync --force`, edited hook + `clean --force`; each also asserts the user `lint` key survives. +2. Add the no-force refusal test expecting the `--force` hint, and the unproven-path test expecting a refusal under force. +3. Run them; record the red failure messages. + +### `2)` Thread `force` to the guard + +> One explicit option flows from the command to the guard; no global state. + +1. `assertProjectHooksUnchanged` takes `{ overwriteEdited }`; when true it skips only the entry-digest and script-hash "edited after install" refusals. +2. `removeObsoleteScripts` deletes an edited obsolete script when `overwriteEdited` is set. +3. Forward it: `RestoreUseCase` → `RestoreAllPluginsUseCase` → `ApplyPluginFilesUseCase` → `materializeViaTranslator` → `PluginTranslator.addPlugin` → `ProjectHooksMaterializer`; and `CleanUseCase` → `assertProjectHooksRemovable` / `removeProjectHooks`. +4. Without the option, the refusal text ends with a hint to rerun with `--force`. +5. Mutation check: drop the forwarding at one layer, a reproduction goes red. + +### `3)` One owner per hook script + +> A project-delivered hook script is recorded in the hooks provenance only. + +1. Test: after a flat antigravity install, `plugins[].files` holds no `.agents/hooks/` path and `projectHooks.scripts` holds the script. +2. In the built-tree flat route, drop the flat hook output paths from the plugin files when the tool delivers hooks to the project. +3. Re-run the restore test of the top branch to confirm it still holds. + +### `4)` Minors + +> Small corrections the reviewer named. + +1. `translate --as flat` with an unparsable `.agents/hooks.json` reports the same "is not valid JSON (...); left untouched." message as setup; test first. +2. Remove the pinned `agy` version from the `antigravity-hooks.ts` comment. +3. Rebuild and record the bundle size; bump the budget only if exceeded, with its comment line. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| ---- | ------------------- | +| 1 | The three reproductions and the no-force test exist and failed before task 2 | +| 2 | `sync --force` and `clean --force` succeed on an edited AIDD hook, the user `lint` key survives, an unproven path still refuses, no-force refuses with a `--force` hint | +| 3 | A fresh antigravity manifest records the hook script once, under `projectHooks.scripts` | +| 4 | The translate error names `.agents/hooks.json`; no agy version in the comment; bundle under budget | diff --git a/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-3.md b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-3.md new file mode 100644 index 000000000..4988dbcad --- /dev/null +++ b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-3.md @@ -0,0 +1,69 @@ +--- +status: pending +--- + +# Instruction: Agents: bundle figures, bracketed frontmatter values + +Owning commit: `feat(cli): emit antigravity agents as portable .agents/agents//agent.md` on `feat/511-antigravity-agents`. + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +cli/ +├── scripts/check-bundle-size.mjs ✏️ per-PR split of the measured growth +├── package.json ✏️ budget only if phase 2 moved the size +├── src/kernel/markdown.ts ✏️ raw emission only for a real JSON array +└── tests/ + ├── contexts/tools/domain/formats/portable-agent.unit.test.ts ✏️ bracketed description, non-string tools + └── kernel/markdown.unit.test.ts ✏️ the same value round-trips as a string +``` + +## User Journey + +```mermaid +flowchart TD + A[agent description '[WIP] foo [x]'] --> B[antigravity build] + B --> C[frontmatter parses, description is the same string] +``` + +## Test Scope + +```mermaid +--- +title: Test scope +--- +journey + section Setup + An agent source with description '[WIP] foo [x]' and tools [1, true] => fixture ready: 5: system + section Happy path + Build the portable frontmatter and parse it back => description equals the source string, tools are strings: 5: system + section Edge case - real JSON array string + A cursor globs value '["a/**","b"]' => serialize => still emitted as a YAML inline array: 1: system +``` + +## Tasks to do + +### `1)` Bundle figures + +> The comment and the commit tell the same per-PR story as the measurements. + +1. Rebuild each branch tip after phase 2 and record its size. +2. Rewrite the budget comment lines: host profile, hooks merge, agents, each with its own measured delta. +3. Reword the owning commit message's bundle sentence to the measured figures. + +### `2)` Bracketed values + +> A string that only looks like a list is quoted. + +1. Test first: `[WIP] foo [x]` and non-string `tools` items through `portableAgentFrontmatter` + `serializeFrontmatter`, parsed back with the project's YAML reader. +2. If red, emit a value raw only when it parses as a JSON array; quote otherwise. +3. Keep the cursor globs test green. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| ---- | ------------------- | +| 1 | The budget comment, the commit message and the measured sizes agree for each of the three branches | +| 2 | A bracketed description parses back as the same string; a JSON-array string still serializes as an inline array | diff --git a/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-4.md b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-4.md new file mode 100644 index 000000000..3a14aa61f --- /dev/null +++ b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-4.md @@ -0,0 +1,82 @@ +--- +status: pending +--- + +# Instruction: Docs and runtime smoke + +Owning commits on `feat/511-antigravity-docs`: the smoke (`test(cli): add a local runtime smoke for antigravity`), the `aidd-context` surfaces (`feat(aidd-context): refresh AGENTS.md for antigravity ...`), the docs (`docs: list antigravity cli as a supported flat host`). + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +. +├── README.md ✏️ Docs link points at the Antigravity overview +├── cli/scripts/smoke-antigravity.sh ✏️ project hook proof, short header, portable script(1) +├── cli/src/contexts/tools/domain/registry.ts ✏️ JSDoc keeps only the null case +└── plugins/aidd-context/skills/ + ├── 04-skill-generate/references/tool-detect.md ✏️ .agents/skills/ wording agrees with ai-mapping + ├── 05-rule-generate/references/tool-paths.md ✏️ glob with paths, always_on without; measured truncation + └── 11-explore/references/ai-mapping.md ✏️ plugins/ paths marked unmeasured; .agents/skills/ wording +``` + +## User Journey + +```mermaid +flowchart TD + A[pnpm smoke:antigravity] --> B[setup writes .agents/hooks.json] + B --> C[agy session] + C --> D{aidd-context hook loaded?} + D -- yes --> E[PASS] + D -- no, even with a global user hook --> F[FAIL] +``` + +## Test Scope + +```mermaid +--- +title: Test scope +--- +journey + section Setup + Logged-in agy, a temp workspace set up with aidd setup --ai antigravity => workspace ready: 5: system + section Happy path + Run the smoke => hooks loaded passes on the aidd-context project hook: 5: cli + section Edge case - project hooks removed + Delete .agents/hooks.json with a global user hook present => run the smoke => hooks loaded fails: 1: cli +``` + +## Tasks to do + +### `1)` Smoke proves the project hook + +> A global user hook can no longer make the check pass. + +1. Read what an `agy` log prints for loaded hooks; match `aidd-context` if it is named. +2. Otherwise compare the loaded count with and without `.agents/hooks.json` and require it to be higher with it. +3. Negative control: delete `.agents/hooks.json`, the check fails. +4. Check whether a `-p` run fires the SessionStart hook; if it does, drop the interactive session part. +5. Shorten the header; no pinned version; pick BSD or util-linux `script` syntax at runtime when the interactive part stays. + +### `2)` Docs precision + +> Each claim states what was measured and what was not. + +1. `tool-paths.md` (rules): a rule with paths is `trigger: glob` with `globs`, one without is `always_on`; the per-file limit is measured, `agy` truncates near 23 to 25 KB and `write-rule.cjs` refuses above 24,000 bytes. +2. `ai-mapping.md`: `~/.gemini/config/plugins//` and `.agents/plugins/` marked unmeasured; `.agents/skills/` wording aligned with `tool-detect.md`. +3. README Docs link to the Antigravity overview; `registry.ts` JSDoc reduced to the `null` case. + +### `3)` Pull request description + +> The description lists every code change it ships. + +1. Add the `write-rule.cjs` antigravity target (path, frontmatter, size refusal) to the description draft. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| ---- | ------------------- | +| 1 | The smoke passes with project hooks and fails without them, whatever the user-global hooks | +| 2 | `ai-mapping.md` and `tool-detect.md` agree on `.agents/skills/`; rules docs name glob vs always_on and the measured truncation | +| 3 | The description draft names the `write-rule.cjs` change | diff --git a/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-5.md b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-5.md new file mode 100644 index 000000000..c3268f957 --- /dev/null +++ b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/phase-5.md @@ -0,0 +1,73 @@ +--- +status: pending +--- + +# Instruction: Replay the stack, gate each branch, draft the replies + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +. +└── cli/tests/e2e/antigravity-foreign-files.e2e.test.ts ✏️ only if its expectation changed with phase 2 +``` + +## User Journey + +```mermaid +flowchart TD + A[fixup commits on the top branch] --> B[autosquash rebase with update-refs] + B --> C[gates on each of the five branches] + C --> D[description and reply drafts for review] + D --> E[user force-pushes] +``` + +## Test Scope + +```mermaid +--- +title: Test scope +--- +journey + section Setup + Move temp/gemini-flat aside => repository gates see no local leftovers: 5: system + section Happy path + Run pre-commit and pre-push gates on each branch tip => all green: 5: cli + section Edge case - ratchet tripped + Comment-line, bundle or mutation floor exceeded => gate fails => fix in the owning commit and replay: 1: cli + section Teardown + Restore temp/gemini-flat => local state as before: 5: system +``` + +## Tasks to do + +### `1)` Replay + +> Each fix lands in the commit that owns it, every branch ref follows. + +1. Autosquash the fixups from the top branch with `--update-refs`. +2. Confirm each branch's commit list matches the original one, same subjects. + +### `2)` Gates + +> Every branch is green on its own. + +1. Per branch tip: `pnpm exec lefthook run pre-commit --all-files`, `pnpm exec lefthook run pre-push`, scripts tests wrapped. +2. Mutation scope `tools-antigravity` stays at or above its floor. +3. Adapt the restore test only if phase 2 changed what it observes. + +### `3)` Drafts + +> The user reviews every word that goes public. + +1. Description updates for the bundle and description findings. +2. One reply per review, each finding answered: fixed (where) or answered (why). + +## Test acceptance criteria + +| Task | Acceptance criteria | +| ---- | ------------------- | +| 1 | The five branches keep their commit subjects and order, each fix inside its owning commit | +| 2 | Every gate passes on every branch tip | +| 3 | Every review finding has a fixed-or-answered line in a draft the user approved | diff --git a/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/plan.md b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/plan.md new file mode 100644 index 000000000..b66e8e083 --- /dev/null +++ b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/plan.md @@ -0,0 +1,32 @@ +--- +objective: "Every review finding on the Antigravity stack is fixed in the commit that owns it, or answered, and each stacked branch passes its gates." +status: implemented +--- + +# Plan: Antigravity stack review fixes + +## Overview + +| Field | Value | +| ---------- | ------------------------------------------------------------------------------------------- | +| **Goal** | Address the review on the five stacked Antigravity pull requests without reshaping the stack | +| **Source** | Review comments on the Antigravity pull request stack, backlog item in `backlog-link.json` | + +## Phases + +| # | Phase | File | +| --- | -------------------------------------------------------- | ---------------------------- | +| 1 | Host profile: user-facing skip message, conformance guard | [`phase-1.md`](./phase-1.md) | +| 2 | Project hooks: `--force` reaches the edit guard | [`phase-2.md`](./phase-2.md) | +| 3 | Agents: bundle figures, bracketed frontmatter values | [`phase-3.md`](./phase-3.md) | +| 4 | Docs and runtime smoke | [`phase-4.md`](./phase-4.md) | +| 5 | Replay the stack, gate each branch, draft the replies | [`phase-5.md`](./phase-5.md) | + +## Decisions + +| Decision | Why | +| --- | --- | +| `--force` lifts only the "edited after install" refusals; ownership proofs still refuse | `--force` means "overwrite my edits to what AIDD wrote", never "touch what AIDD cannot prove it wrote" | +| A confirmed interactive `clean` without `--force` still refuses an edited hook | the escape hatch stays explicit and scriptable | +| Each fix is a fixup of the commit that owns the code, autosquashed with `--update-refs` | every pull request keeps its own diff; no new branch enters the stack | +| A project-delivered hook script belongs to the hooks provenance only, never to `plugins[].files` | one file, one owner: two records let `clean` delete without the edit check and `sync` see drift twice | diff --git a/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/review.md b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/review.md new file mode 100644 index 000000000..a0cb5c1de --- /dev/null +++ b/aidd_docs/tasks/2026_10/2026_10_14_antigravity-review-fixes/review.md @@ -0,0 +1,40 @@ +# Review: Antigravity stack review fixes + +- Rounds: 1 +- Started: 2026-10-14 + +## Round 1 · r-7c3e + +- Date: 2026-10-14 +- By: Thierry Kwiatkowski +- Diff: `origin/feat/511-antigravity-host...test/511-antigravity-restore` per branch (`origin/...` for each of the five; `backup/*` were rewritten by `--update-refs` and equal the fixed tips) +- Axes: code, functional, relevancy +- Verdict: changes-requested +- Score: 10/11 met, 0 unmet, 1 unverified at runtime, 0 out of the diff + +### Criteria + +- [x] C1 skip reason has no ticket id, pinned by test — `cli/src/contexts/tools/domain/profiles/antigravity/profile.ts:47` on the host tip, `profile.unit.test.ts:37` uses `toBe` +- [x] C2 early return replaced by a named opt-out — `registry-conformance.unit.test.ts:47,99`; emptying the set fails `is ingestible when it declares a plugins capability` (1 failed / 80 passed) +- [x] C3 `sync --force` / `clean --force` lift only the edit refusals — `remove-project-hooks.ts:59-83`; e2e `antigravity-edited-hooks.e2e.test.ts` 6/6 green on the tip, 6/6 red on `origin/feat/511-antigravity-memory-hook`; removing `force: ctx.force` (restore) or the clean guard turns the matching e2e red; plugin add/update/remove call sites pass no guard +- [x] C4 hook script recorded only in `projectHooks.scripts` — `built-tree-materialization-translator.ts:159`; reverting it fails `records a project-delivered hook script once` +- [x] C5 `translate --as flat` names `.agents/hooks.json` and leaves it untouched; no pinned agy version in `antigravity-hooks.ts:9` — `flat-build-strategy.ts:225,232` +- [x] C6 bundle figures consistent per branch — `check-bundle-size.mjs:37-40`, agents commit message; arithmetic checks (762.4-757.9=4.5, 764.2-762.4=1.8, 0.9% headroom) +- [x] C7 bracketed non-JSON-array strings quoted, JSON arrays raw — `cli/src/kernel/markdown.ts:31,62`, `markdown.unit.test.ts:153`, `portable-agent.unit.test.ts:47` +- Unverified at runtime: C8 smoke "project hooks loaded" proves the project hook against a global user hook — the only negative control ran with 0 global hooks (`0 with, 0 without`), and the baseline runs in print mode while the measured session is interactive +- [x] C9 #961 description mentions `write-rule.cjs` — `review-replies.md` #961 description edit (draft) +- [x] C10 docs precision — `05-rule-generate/references/tool-paths.md:14,16`, `11-explore/references/ai-mapping.md:7,62` agrees with `04-skill-generate/references/tool-detect.md:14`, `README.md:197`, `smoke-antigravity.sh:2-9,39-46` +- [x] C11 #962 test unchanged — `git diff origin/test/511-antigravity-restore test/511-antigravity-restore` touches no test of #962 + +### Findings + +- `cli/scripts/smoke-antigravity.sh:93-103` : the difference check compares an interactive session's hook count with a print-mode (`-p`) baseline, and the reply claims global hooks "cancel out"; the only negative control ran on a machine with no global hook, which is the exact condition the reviewer said proves nothing → run the baseline in the same interactive pty mode, or record a run with a user-global hook present (reviewer's own setup) before claiming it — 🟡 major, fit +- `cli/src/contexts/framework/application/framework/translator/mode-b-flat-materialization-translator.ts:74` : dropping `hooksGuard` from this call leaves all 2418 framework and e2e tests green, so the `--force` threading on the no-marketplace route has no guard → add a Mode-B `--force` test (unit or e2e without a registered marketplace) that goes red on this mutation — 🟡 major, code-health +- `cli/src/contexts/framework/application/shared/remove-project-hooks.ts:45` : adding `if (overwriteEdited) return { existing };` inside the legacy branch leaves every test green; C3 names the legacy-install refusal under `--force` explicitly → add a `{ overwriteEdited: true }` case to the legacy `it.each` at `remove-project-hooks.unit.test.ts:67` — 🟡 major, code-health +- `backup/511-antigravity-{host,memory-hook,agents,docs}` : reflog shows `rewritten during rebase`; `--update-refs` moved every backup onto the fixed commits, so the pre-fix tips live only on `origin/*` and in reflog, and a force-push removes the remote copy → recreate backups from `origin/*` (e.g. `git branch -f backup/511-antigravity-host origin/feat/511-antigravity-host`) before pushing — 🟡 major, fit +- `review-replies.md` #960 table : "#957 757.9 KB, measured with tsup on the replayed stack", while the replayed host tip measures 757.8 KB → say 757.8 measured now, or label 757.9 as the figure recorded at the raise — 🟢 minor, fit +- `review-replies.md` #958 telemetry bullet and `antigravity-hooks.ts:7` : "no agy equivalent of `Stop` was measured" and "only the tool-free event is carried over", yet `08-hook-generate/references/tool-paths.md:33` states agy documents `Stop`, which is tool-free → say `Stop` is documented but unmeasured, so it is not mapped yet — 🟢 minor, rot +- `review-replies.md` #961 bullet "the header is 4 lines" : the header comment at `smoke-antigravity.sh:2-9` is 8 lines (the rewritten paragraph is 4) → say "the rationale paragraph is 4 lines" — 🟢 minor, fit +- `review-replies.md` #961 bullet "checked in a Debian container" : no recorded output in the plan folder or PR → attach the command and its output, or drop the claim — 🟢 minor, fit +- `cli/src/contexts/translate/application/strategies/flat-build-strategy.ts:232` : `assertParsableJson` duplicates `remove-project-hooks.ts:181` with the same message; translate cannot import framework → move one copy to `kernel/` and import it from both — 🟢 minor, rot +- `test/511-antigravity-restore` (#962) : now carries `docs: plan the antigravity review fixes`, a planning commit in a test PR, and the drafted #962 description does not mention it → name it in the #962 description, or move the plan commit to the docs branch — 🟢 minor, fit