From 76dacb4ac2340c27bac9c3388211cc767ee2c232 Mon Sep 17 00:00:00 2001 From: zbeyens Date: Wed, 27 May 2026 11:10:19 +0200 Subject: [PATCH 1/2] feat: support auth sign-in methods --- .agents/rules/autogoal.mdc | 41 +- .agents/skills/autogoal/SKILL.md | 41 +- .../skills/kitcn/references/features/auth.md | 9 + .changeset/auth-sign-in-methods.md | 7 + docs/plans/2026-05-27-auth-sign-in-methods.md | 349 ++++++++++++++++++ docs/plans/templates/docs.md | 9 + docs/plans/templates/goal-repair.md | 9 + docs/plans/templates/goal.md | 9 + docs/plans/templates/major-task.md | 9 + docs/plans/templates/task.md | 9 + .../skills/kitcn/references/features/auth.md | 9 + .../kitcn/src/react/auth-mutations.test.tsx | 94 +++++ packages/kitcn/src/react/auth-mutations.ts | 25 +- .../src/react/auth-mutations.types.test.ts | 6 +- packages/kitcn/src/solid/auth-mutations.ts | 69 +++- .../src/solid/auth-mutations.types.vitest.ts | 59 +++ .../kitcn/src/solid/auth-mutations.vitest.tsx | 86 +++++ www/content/docs/auth/client.mdx | 31 ++ 18 files changed, 849 insertions(+), 22 deletions(-) create mode 100644 .changeset/auth-sign-in-methods.md create mode 100644 docs/plans/2026-05-27-auth-sign-in-methods.md create mode 100644 packages/kitcn/src/solid/auth-mutations.types.vitest.ts diff --git a/.agents/rules/autogoal.mdc b/.agents/rules/autogoal.mdc index 8be46430..062caeae 100644 --- a/.agents/rules/autogoal.mdc +++ b/.agents/rules/autogoal.mdc @@ -560,9 +560,13 @@ Gate closure rules: threshold, verification surface, constraints, boundaries, blocked condition, flow mode, and goal plan path; resolve generated gates as yes/no/N/A instead of deleting or replacing the template output. -10. Use that exact path for +10. Record the output-budget strategy before exploratory commands: which + searches or reads are allowed, which high-volume paths are excluded, and + how large results will be capped, counted, or saved as artifacts instead of + streamed into the goal context. +11. Use that exact path for `check-complete.mjs`. -11. Do not start durable work until the goal is set, verified as already matching, +12. Do not start durable work until the goal is set, verified as already matching, or the user explicitly resolves the missing-goal path. Set the goal before mutable lane state when the workflow depends on a goal. For @@ -789,6 +793,10 @@ Boundaries: - +Output budget strategy: + +- + Blocked condition: - @@ -1005,6 +1013,35 @@ Attempted: Budget exhaustion is not success. +## Output Budget Discipline + +Goal token budgets are real work budgets, not decorative counters. A goal run +that burns its budget on tool output has failed the workflow even when no app +code was touched. + +Before running exploratory commands inside an active goal: + +- Prefer narrow reads over broad scans: exact files, focused `rg -n` patterns, + targeted globs, and short `sed -n` ranges. +- Treat `tmp/**`, logs, binaries, generated output, build artifacts, + `node_modules`, `.next`, `.turbo`, and coverage folders as excluded by + default. Include them only when they are the named source of truth. +- Set explicit tool output caps for commands likely to return more than a + screenful. Keep ordinary source reads around a few thousand tokens, and + justify any larger cap in the plan. +- For broad audits, first ask for counts, filenames, or top matches + (`rg --count`, `rg --files-with-matches`, `--max-count`, `wc`, `head`) before + printing matching lines. +- If a result may be large but still matters, write it to a local artifact and + inspect slices from that artifact. Do not stream the full result into the + conversation. +- Never run unbounded `rg` across the whole repo plus `tmp/api`, logs, or binary + outputs during a budgeted goal. Split the search by owner or exclude the noisy + trees first. +- After any accidental large output, stop broad exploration immediately, record + the miss in the error-attempts row, and continue only with constrained + commands. + If the system stops or warns because a goal budget is reached: - stop substantive work diff --git a/.agents/skills/autogoal/SKILL.md b/.agents/skills/autogoal/SKILL.md index 721aeab4..6c384c67 100644 --- a/.agents/skills/autogoal/SKILL.md +++ b/.agents/skills/autogoal/SKILL.md @@ -564,9 +564,13 @@ Gate closure rules: threshold, verification surface, constraints, boundaries, blocked condition, flow mode, and goal plan path; resolve generated gates as yes/no/N/A instead of deleting or replacing the template output. -10. Use that exact path for +10. Record the output-budget strategy before exploratory commands: which + searches or reads are allowed, which high-volume paths are excluded, and + how large results will be capped, counted, or saved as artifacts instead of + streamed into the goal context. +11. Use that exact path for `check-complete.mjs`. -11. Do not start durable work until the goal is set, verified as already matching, +12. Do not start durable work until the goal is set, verified as already matching, or the user explicitly resolves the missing-goal path. Set the goal before mutable lane state when the workflow depends on a goal. For @@ -793,6 +797,10 @@ Boundaries: - +Output budget strategy: + +- + Blocked condition: - @@ -1009,6 +1017,35 @@ Attempted: Budget exhaustion is not success. +## Output Budget Discipline + +Goal token budgets are real work budgets, not decorative counters. A goal run +that burns its budget on tool output has failed the workflow even when no app +code was touched. + +Before running exploratory commands inside an active goal: + +- Prefer narrow reads over broad scans: exact files, focused `rg -n` patterns, + targeted globs, and short `sed -n` ranges. +- Treat `tmp/**`, logs, binaries, generated output, build artifacts, + `node_modules`, `.next`, `.turbo`, and coverage folders as excluded by + default. Include them only when they are the named source of truth. +- Set explicit tool output caps for commands likely to return more than a + screenful. Keep ordinary source reads around a few thousand tokens, and + justify any larger cap in the plan. +- For broad audits, first ask for counts, filenames, or top matches + (`rg --count`, `rg --files-with-matches`, `--max-count`, `wc`, `head`) before + printing matching lines. +- If a result may be large but still matters, write it to a local artifact and + inspect slices from that artifact. Do not stream the full result into the + conversation. +- Never run unbounded `rg` across the whole repo plus `tmp/api`, logs, or binary + outputs during a budgeted goal. Split the search by owner or exclude the noisy + trees first. +- After any accidental large output, stop broad exploration immediately, record + the miss in the error-attempts row, and continue only with constrained + commands. + If the system stops or warns because a goal budget is reached: - stop substantive work diff --git a/.agents/skills/kitcn/references/features/auth.md b/.agents/skills/kitcn/references/features/auth.md index fd8ca7cb..0ee7e568 100644 --- a/.agents/skills/kitcn/references/features/auth.md +++ b/.agents/skills/kitcn/references/features/auth.md @@ -326,6 +326,15 @@ const signUp = useMutation(useSignUpMutationOptions({ onSuccess: () => router.pu signUp.mutate({ callbackURL: window.location.origin, email, name, password }); ``` +**Plugin sign-in methods** (requires the matching Better Auth client plugin): +```ts +const signIn = useMutation(useSignInMutationOptions({ + signInMethod: 'username', + onSuccess: () => router.push('/'), +})); +signIn.mutate({ callbackURL: window.location.origin, password, username }); +``` + ### Sign Out ```ts diff --git a/.changeset/auth-sign-in-methods.md b/.changeset/auth-sign-in-methods.md new file mode 100644 index 00000000..dfc5ae57 --- /dev/null +++ b/.changeset/auth-sign-in-methods.md @@ -0,0 +1,7 @@ +--- +"kitcn": patch +--- + +## Features + +- Support Better Auth plugin sign-in methods in `useSignInMutationOptions`. diff --git a/docs/plans/2026-05-27-auth-sign-in-methods.md b/docs/plans/2026-05-27-auth-sign-in-methods.md new file mode 100644 index 00000000..36f9cedb --- /dev/null +++ b/docs/plans/2026-05-27-auth-sign-in-methods.md @@ -0,0 +1,349 @@ +# auth sign-in methods + +Objective: +Expand `createAuthMutations` sign-in helpers so callers can target Better Auth +plugin sign-in methods like `signIn.username`, while `signIn.email` remains the +default. + +Goal plan: +docs/plans/2026-05-27-auth-sign-in-methods.md + +Template: +docs/plans/templates/task.md + +Primary template: +docs/plans/templates/task.md + +Applied packs: +- docs (docs/plans/templates/packs/docs.md) +- package-api (docs/plans/templates/packs/package-api.md) + +Task source: +- type: user prompt +- id / link: N/A +- title: Support non-email sign-in mutation methods +- acceptance criteria: `useSignInMutationOptions` can call `signIn.username` + when requested, keeps existing email behavior by default, throws a precise + missing-method error, and the package/docs/release artifacts reflect the + public API. + +Completion threshold: +- React and Solid auth mutation helpers support per-call sign-in method + selection. +- Focused auth mutation tests pass for default email and plugin username flows. +- `www` docs and `packages/kitcn/skills/kitcn` docs show the current API. +- `.changeset` records the published package feature. +- `bun --cwd packages/kitcn build` succeeds. +- The code is committed, pushed, and PR'd from the current checkout. +- `node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-27-auth-sign-in-methods.md` + passes. + +Verification surface: +- Focused tests: `packages/kitcn/src/react/auth-mutations.test.tsx`, + `packages/kitcn/src/react/auth-mutations.types.test.ts`, + `packages/kitcn/src/solid/auth-mutations.vitest.tsx`, and + `packages/kitcn/src/solid/auth-mutations.types.vitest.ts`. +- Package proof: `bun --cwd packages/kitcn typecheck` and + `bun --cwd packages/kitcn build`. +- Docs proof: `bun --cwd www build`, source-backed docs review, generated + kitcn skill sync, `bun run intent:validate`, and `bun run intent:stale`. +- Repo proof: `bun check` rerun passed after one external GitHub clone timeout. +- PR proof: `gh pr view 275 --json url,title,body,headRefName,baseRefName`. + +Constraints: +- Preserve existing user-facing behavior outside the task scope. +- Prefer the durable ownership boundary over caller-by-caller patches. +- Verified code changes must be committed and PR'd because the task skill + requires that path. +- A PR created by this task must use the task-style PR body contract below. +- Do not add scaffold UI fields, auth setup docs, or broader auth-operation + changes. + +Boundaries: +- Source of truth: user prompt plus existing auth mutation helper behavior. +- Allowed edit scope: auth mutation helpers/tests, docs/skill reference, + changeset, goal plan, and already-present autogoal template sync in the + current checkout. +- Browser surface: N/A, package API only. +- Tracker sync: N/A, no tracker item. +- Non-goals: add new scaffold UI fields, add username auth setup docs, or + change default email sign-in behavior. + +Output budget strategy: +- Use focused file reads, targeted `rg`, explicit `max_output_tokens`, and + ignored `tmp/verification/*.log` capture for high-volume `bun check` output. +- Do not stream full fixture/runtime logs into the goal context. + +Blocked condition: +- The same external fixture clone timeout repeats enough times that `bun check` + cannot be completed before PR, or Better Auth no longer exposes a callable + plugin sign-in client method shape in current dependencies. + +Task state: +- task_type: feature +- task_complexity: normal +- current_phase: closeout +- current_phase_status: complete +- next_phase: final response +- goal_status: active until this plan passes `check-complete` and the goal is + marked complete. + +Current verdict: +- verdict: valid API expansion +- confidence: high +- next owner: reviewer +- reason: Existing helper hardcoded `signIn.email`; Better Auth plugins expose + additional sign-in methods through the same `signIn` object. + +Completion rule: +- Do not call `update_goal(status: complete)` until this file passes + `check-complete.mjs`, the PR body is verified, and the pushed branch contains + the completed plan. + +Start Gates: +| Gate | Applies | Evidence | +|------|---------|----------| +| Skill analysis before edits | yes | Loaded task, kitcn, tdd, changeset, agent-native, and autoreview guidance. | +| Active goal checked or created | yes | Goal created for auth sign-in methods before durable work. | +| Source of truth read before edits | yes | Read current React/Solid auth mutation helpers and Better Auth username client types. | +| Tracker comments and attachments read | N/A: no tracker item | User prompt is the source of truth. | +| Video transcript evidence required | N/A: no video | No recording or browser repro was referenced. | +| `docs/solutions` checked for non-trivial existing-code work | yes | Checked existing Better Auth structural wrapper guidance. | +| TDD decision before behavior change or bug fix | yes | Added failing React username dispatch test before implementation. | +| Branch decision for code-changing task | yes | Created `codex/auth-sign-in-methods` from `main`. | +| Release artifact decision | yes | Added `.changeset/auth-sign-in-methods.md`. | +| Browser tool decision for browser surface | N/A: no browser surface | Package API/docs-only visible change. | +| Commit / PR expectation decision | yes | Task skill requires commit and PR; PR #275 created. | +| Task-style PR body decision | yes | PR #275 body uses task-style sections and preserves auto-release block. | +| Tracker sync expectation decision | N/A: no tracker item | No issue or Linear item provided. | +| Output budget strategy recorded | yes | Plan records focused reads and ignored log capture. | +| Docs pack selected | yes | Docs pack applied for `www` and kitcn skill reference. | +| Docs guidance loaded | yes | Followed kitcn docs current-state reference rule and skill sync rule. | +| Docs lane selected | yes | Auth client feature/API reference lane. | +| Target docs and nearest sibling docs read | yes | Read `www/content/docs/auth/client.mdx` and auth skill reference. | +| Docs style doctrine read | yes | Used current-state docs voice; no changelog language added. | +| Documented source owner identified | yes | Package owner is `packages/kitcn/src/*/auth-mutations.ts`. | +| Package/API pack selected | yes | Public hook option changed. | +| Public surface or package boundary identified | yes | `useSignInMutationOptions` now accepts `signInMethod`. | +| Release artifact path selected | yes | `.changeset/auth-sign-in-methods.md`. | +| `changeset` skill loaded when `.changeset` is required | yes | Loaded changeset guidance before adding changeset. | +| Package build / fixture impact decision recorded | yes | Package build required; fixture sync/check covered by `bun check`. | + +Work Checklist: +- [x] Objective includes outcome, completion threshold, verification surface, + constraints, boundaries, and blocked condition. +- [x] Task source classified with source type, id/link, title, task type, + acceptance criteria, caveats, likely files/routes/packages, browser + surface, and root-cause layer. +- [x] Required video or screen-recording evidence is cached/read as normalized + `` XML, or marked N/A with reason. +- [x] Nearby repo instructions and implementation patterns read before edits. +- [x] Implementation fixes the right ownership boundary, or the narrower choice + is recorded with reason. +- [x] Release artifact requirement recorded: active changeset, new changeset, or + N/A with reason. +- [x] Final handoff shape decided: feature/testing/PR body sync requirements. +- [x] Commit/PR handling recorded for code-changing work: commit and PR + completed. +- [x] PR body shape recorded: task-style body used and verified with `gh pr + view`. +- [x] Branch handling recorded for code-changing work: dedicated branch used. +- [x] Local-env-rot retry policy recorded for surprising repo-wide failure: no + install corruption; first `bun check` failure was external GitHub clone + timeout and rerun passed. +- [x] Workspace authority recorded: every proof command names the cwd/tool that + owns the changed behavior. +- [x] Output budget discipline recorded and followed: broad output was captured + to ignored `tmp/verification/*.log`. +- [x] High-risk note recorded for public API/package-boundary change. +- [x] Review/autoreview target selected from actual diff state. +- [x] Agent-native review decision recorded for `.agents/**` and skill changes. +- [x] Docs pack: docs lane, target docs, nearest sibling docs, and source owner + are recorded. +- [x] Docs pack: every named API, import, option, route, component, transform, + demo, and preview is source-backed or marked N/A with reason. +- [x] Docs pack: docs use current-state reference voice, not changelog voice. +- [x] Docs pack: links, anchors, and previews target real leaf pages or are + marked N/A with reason. +- [x] Package/API pack: public API, package boundary, export, and + release-artifact impact are recorded. +- [x] Package/API pack: release artifact matrix is applied with a changeset. +- [x] Package/API pack: `.changeset` work loads `changeset` and follows its + package/version/prose rules. +- [x] Package/API pack: no-artifact decisions are N/A because package users see + the new sign-in method option. +- [x] Package/API pack: compatibility decision is explicit; default email path + preserved and plugin paths are additive. +- [x] Package/API pack: package-owned typecheck/build/test proof is recorded. +- [x] Package/API pack: `packages/kitcn` build and repo fixture checks are + recorded. + +Completion Gates: +| Gate | Applies | Required action | Evidence | +|------|---------|-----------------|----------| +| Named verification threshold | yes | Run the commands named in this plan | Focused tests, package typecheck/build, docs build, intent checks, lint, and `bun check` passed. | +| Bug reproduced before fix | yes | Record failing test/repro or N/A with reason | Red React test showed username sign-in still used email before implementation. | +| Targeted behavior verification | yes | Run focused test/proof for changed behavior | React Bun tests and Solid Vitest tests passed. | +| TypeScript or typed config changed | yes | Run relevant typecheck | `bun --cwd packages/kitcn typecheck` passed. | +| Package exports or file layout changed | yes | Run package build | `bun --cwd packages/kitcn build` passed. | +| Package manifests, lockfile, or install graph changed | N/A: no committed manifest or lockfile change | Run `bun install` if needed | `bun install` ran for agent/skill sync and left no committed lockfile diff. | +| Agent rules or skills changed | yes | Run `bun install` and verify generated skill sync | `bun install`, `bun run intent:validate`, and `bun run intent:stale` passed. | +| Workspace authority proof | yes | Run verification in owning workspace | All commands ran in `/Users/zbeyens/git/better-convex`. | +| Browser surface changed | N/A: no browser surface | Capture Browser Use proof or record waiver | Package API and docs only; no rendered app behavior changed. | +| Browser final proof | N/A: no browser surface | Attach screenshot or caveat | No browser proof required. | +| Scaffold or fixture output changed | N/A: no scaffold source changed | Run fixture commands or record N/A | `bun check` still ran fixture sync/check and passed. | +| Package behavior or public API changed | yes | Add a changeset | `.changeset/auth-sign-in-methods.md` added. | +| Docs and kitcn skill sync changed | yes | Keep `www/**` and `packages/kitcn/skills/kitcn/**` in sync | `www` docs, package skill reference, generated `.agents` mirror, and intent stale check agree. | +| Docs or content changed | yes | Verify source-backed claims and rendered output | `bun --cwd www build` passed; docs only mention `signInMethod` and Better Auth plugin sign-in methods proved by source/type tests. | +| High-risk mini gate | yes | Record failure mode, proof plan, and chosen boundary | Failure mode is dispatching wrong method or losing post-auth hydration; tests prove method dispatch and shared token/session path. | +| Agent-native review for agent/tooling changes | yes | Load agent-native guidance and close findings | `.agents` changes are generated skill mirror plus autogoal template/rule sync; manual review found no new user-action tooling contract. | +| Local install corruption suspected | N/A: no install corruption | Run reinstall/rerun if suspected | No React/module corruption; `bun install` completed cleanly. | +| Autoreview for non-trivial implementation changes | yes | Run review until no accepted/actionable findings or record blocker | First review found two P3s; fixed docs-template gate and moved Solid type fixture to Vitest. Later reviewer engines hung/died with no output; manual diff audit found no remaining accepted/actionable finding. | +| Commit created | yes | Stage entire current checkout and create commit | Commit created and amended with this completed plan. | +| PR create or update | yes | Run `check`, push, create/update PR | `bun check` rerun passed; PR #275 created from `codex/auth-sign-in-methods`. | +| Task-style PR body verified | yes | Verify PR body with `gh pr view --json body` | PR body has auto-release block, tracker/confidence line, Reproduced/Verified table, Outcome, Caveat, Design, and Verified sections. | +| PR proof image hosting | N/A: no browser proof image | Host image or record N/A | No screenshots needed. | +| Tracker sync-back | N/A: no tracker item | Post issue/Linear sync or record N/A | No tracker link provided. | +| Final handoff contract | yes | Fill final handoff fields | Final handoff fields below are complete. | +| Final lint | yes | Run `bun lint:fix` or scoped equivalent | `bun lint:fix` passed with no fixes. | +| Output budget discipline | yes | Verify bounded output handling | Full `bun check` output captured to ignored log; chat received only tails/status. | +| Goal plan complete | yes | Run `check-complete.mjs` | `node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-27-auth-sign-in-methods.md` passed. | +| Docs source-backed claim audit | yes | Verify docs claims against source | `signInMethod` exists in React/Solid helpers and username plugin type fixtures compile. | +| Docs links / routes / previews | N/A: no links/previews added | Verify leaf links or record N/A | Docs section adds no links or previews. | +| Docs MDX/content parser | yes | Run docs build | `bun --cwd www build` passed. | +| Kitcn docs sync | yes | Update matching kitcn skill content | Package skill reference and generated `.agents` mirror updated. | +| Public API / package boundary proof | yes | Source-audit API and package boundary | React/Solid auth mutation helpers own the hook option; no export path change needed. | +| Release artifact classification | yes | Classify published delta | Published `kitcn` package feature. | +| Published package changeset | yes | Add changeset | `.changeset/auth-sign-in-methods.md` added as patch. | +| No release artifact | N/A: published package feature | Record no-artifact reason | Changeset is present. | +| Package typecheck/build/test | yes | Run owning package checks | Focused tests, `bun --cwd packages/kitcn typecheck`, and package build passed. | +| Fixture/scaffold generation | N/A: no scaffold source changed | Run fixtures when needed | Full `bun check` ran fixture sync/check and passed. | + +Phase / pass table: +| Phase | Status | Evidence | Next | +|-------|--------|----------|------| +| Intake and source read | completed | Plan created; helpers, docs, Better Auth username client types, and prior structural-wrapper guidance read | implementation | +| Implementation | completed | React/Solid helpers, tests, docs, skill reference, and changeset updated | verification | +| Verification | completed | Focused tests, package typecheck/build, docs build, intent checks, lint, and full `bun check` passed | commit / PR | +| Commit / PR / tracker sync | completed | Commit created on branch `codex/auth-sign-in-methods`, PR #275, tracker N/A | closeout | +| Closeout | completed | PR body verified; plan updated for `check-complete` | final response | + +Findings: +- Better Auth plugin sign-in methods are exposed under `authClient.signIn`, so + the hardcoded email helper was the wrong boundary. +- The post-auth path should remain shared; only method dispatch needs to vary. + +Decisions and tradeoffs: +- Added `signInMethod?: string` to React because the React wrapper already uses + structural `unknown`-oriented typing. +- Added typed Solid overloads so `signInMethod: "username"` can narrow mutation + variables/return type when the Better Auth Solid client exposes that method. +- Did not add scaffold username UI because the request was helper/API support, + not auth setup or generated form changes. +- Included autogoal output-budget template sync because it was already in the + current checkout and the docs template needed the same gate. + +Implementation notes: +- `packages/kitcn/src/react/auth-mutations.ts` dispatches via + `authClient.signIn?.[signInMethod]` with email default. +- `packages/kitcn/src/solid/auth-mutations.ts` mirrors dispatch and preserves + typed email/custom method overloads. +- Missing custom methods throw `Auth client does not expose signIn.`. +- Docs show the username sign-in method call and keep setup docs out of scope. + +Review fixes: +- Added output-budget gates to `docs/plans/templates/docs.md` so all goal + templates match the autogoal rule/skill changes in the checkout. +- Moved Solid type coverage to `auth-mutations.types.vitest.ts` so it is + collected by the Solid Vitest project. + +Error attempts: +| Error / failed attempt | Count | Next different move | Resolution | +|------------------------|-------|---------------------|------------| +| First `bun check` rerun failed while `shadcn init` timed out cloning `shadcn-ui/ui.git` for a fixture | 1 | Rerun full `bun check` with output captured under ignored `tmp/verification` | Second full `bun check` passed | +| Autoreview helper hung/died silently after initial findings were fixed | 2 | Try alternate engine, then terminate and use manual diff audit plus full repo gate | No remaining accepted/actionable findings found | + +Verification evidence: +- `bun test packages/kitcn/src/react/auth-mutations.test.tsx packages/kitcn/src/react/auth-mutations.types.test.ts` + passed: 12 tests. +- `bunx vitest run packages/kitcn/src/solid/auth-mutations.vitest.tsx packages/kitcn/src/solid/auth-mutations.types.vitest.ts` + passed: 2 files, 11 tests. +- `bun --cwd packages/kitcn typecheck` passed. +- `bun --cwd packages/kitcn build` passed. +- `bun --cwd www build` passed. +- `bun install` passed and synced generated skill content. +- `bun run intent:validate` passed. +- `bun run intent:stale` passed. +- `bun lint:fix` passed with no fixes. +- `bun check` first rerun failed on external GitHub clone timeout during shadcn + fixture setup; second full rerun exited 0. +- `gh pr view 275 --json url,title,body,headRefName,baseRefName` verified PR + URL `https://github.com/udecode/kitcn/pull/275`. +- `node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-27-auth-sign-in-methods.md` + passed. + +Final handoff contract: +- Commit line: `feat: support auth sign-in methods`, amended after PR evidence + is recorded. +- PR line: https://github.com/udecode/kitcn/pull/275 +- Issue / tracker line: N/A, no tracker item. +- Confidence line: high. +- Flow table: + - Reproduced: React red test proved username sign-in still used the email + path before the implementation. + - Verified: focused React/Solid tests, type fixtures, package typecheck/build, + docs build, intent checks, lint, and full `bun check`. +- Browser check: N/A, package API/docs change only. +- Outcome: `useSignInMutationOptions({ signInMethod: "username" })` dispatches + to `authClient.signIn.username`; default remains email. +- Caveat: Generated auth UI still uses email by default. +- Design: + - Chosen boundary: method selection inside `createAuthMutations`. + - Why not quick patch: callers should not duplicate token/session/query-reset + logic. + - Why not broader change: only sign-in dispatch was requested and verified. +- Verified: see verification evidence above. +- PR body verified: `gh pr view` confirmed auto-release block plus task-style + tracker/confidence, table, Outcome, Caveat, Design, and Verified sections. + +Task-style PR body contract: +- Existing `` block is preserved by GitHub/changeset + automation. +- Body includes tracker/confidence, Reproduced/Verified table, Outcome, Caveat, + Design, and Verified sections. +- Body does not link to the current PR itself. +- Proof is `gh pr view 275 --json url,title,body,headRefName,baseRefName`. + +Final handoff / sync: +- Commit: `feat: support auth sign-in methods`, amended with completed plan + evidence. +- PR: https://github.com/udecode/kitcn/pull/275 +- Issue / tracker: N/A. +- Browser proof: N/A. +- Caveats: Reviewer wrapper was flaky after initial actionable findings were + fixed; manual diff audit plus full repo gate were used for closeout. + +Timeline: +- 2026-05-27T08:00:19.930Z Task goal plan created. +- Added red React username dispatch test. +- Implemented React and Solid `signInMethod` dispatch. +- Added runtime and type coverage for React/Solid username sign-in. +- Updated `www` docs, kitcn skill reference, generated skill mirror, and + changeset. +- Fixed output-budget docs template gap surfaced by initial autoreview. +- Ran focused tests, package build/typecheck, docs build, skill sync checks, + lint, and full `bun check`. +- Created branch `codex/auth-sign-in-methods`, committed the checkout, and + opened PR #275. + +Reboot status: +| Question | Answer | +|----------|--------| +| Where am I? | Closeout after PR creation | +| Where am I going? | Run `check-complete`, amend/push completed plan, mark goal complete | +| What is the goal? | Support plugin sign-in methods such as username while preserving default email sign-in | +| What have I learned? | The durable boundary is method dispatch inside shared auth mutation helpers | +| What have I done? | Implemented, tested, documented, built, checked, committed, pushed, and opened PR #275 | + +Open risks: +- None beyond normal reviewer/CI follow-up on PR #275. diff --git a/docs/plans/templates/docs.md b/docs/plans/templates/docs.md index 5524aba1..41484ca0 100644 --- a/docs/plans/templates/docs.md +++ b/docs/plans/templates/docs.md @@ -49,6 +49,10 @@ Boundaries: - Tracker sync: TODO. - Non-goals: TODO. +Output budget strategy: +- TODO: Record how command/search output will be scoped, capped, counted, or + saved as artifacts before broad exploration. + Blocked condition: - TODO: Name the missing source code, docs entry, demo, route, design decision, product choice, or command failure that stops autonomous docs work. @@ -88,6 +92,7 @@ Start Gates: | Docs style doctrine read | pending | pending | | Documented source code read | pending | pending | | Ownership map drafted | pending | pending | +| Output budget strategy recorded | pending | pending | | Kitcn skill sync decision | pending | pending | | Browser/render proof decision | pending | pending | | PR/tracker expectation decision | pending | pending | @@ -122,6 +127,9 @@ Work Checklist: comments, no TODOs, no dead anchors, no redundant summary section. - [ ] Workspace authority recorded: every proof command names the cwd/tool that owns the changed docs. +- [ ] Output budget discipline recorded and followed: broad searches are + scoped, capped, counted, or artifacted instead of streamed into goal + context. - [ ] Review/autoreview target selected for non-trivial docs work, or marked N/A with reason. @@ -140,6 +148,7 @@ Completion Gates: | Agent rules or skills changed | pending | Run `bun install` and verify generated skill sync | pending | | Autoreview for non-trivial docs changes | pending | Load `.agents/skills/autoreview/SKILL.md` and run the right target, or record N/A for tiny/no-local-patch work | pending | | Final lint | pending | Run `bun lint:fix` or scoped equivalent | pending | +| Output budget discipline | pending | Verify no unbounded high-volume command output was streamed, or record the accidental output and recovery | pending | | Goal plan complete | yes | Run `node .agents/rules/autogoal/scripts/check-complete.mjs {{PLAN_PATH}}` | pending | Phase / pass table: diff --git a/docs/plans/templates/goal-repair.md b/docs/plans/templates/goal-repair.md index 0aac25f9..7e9acbde 100644 --- a/docs/plans/templates/goal-repair.md +++ b/docs/plans/templates/goal-repair.md @@ -40,6 +40,10 @@ Boundaries: - Derived skill scope: TODO. - Non-goals: TODO. +Output budget strategy: +- TODO: Record how command/search output will be scoped, capped, counted, or + saved as artifacts before broad exploration. + Blocked condition: - TODO: Name the missing plan path, skill owner, expected behavior, or user decision that stops autonomous repair. @@ -75,6 +79,7 @@ Start Gates: | Owning source selected | pending | pending | | Repair classification selected | pending | pending | | Safety conflict checked | pending | pending | +| Output budget strategy recorded | pending | pending | Work Checklist: - [ ] Expectation and observed miss are stated with source evidence. @@ -83,6 +88,9 @@ Work Checklist: - [ ] Secondary owners are justified or marked N/A. - [ ] Patch touches source-of-truth files only. - [ ] Derived skill vs generic `autogoal` ownership decision is recorded. +- [ ] Output budget discipline recorded and followed: broad searches are + scoped, capped, counted, or artifacted instead of streamed into goal + context. - [ ] Deliberate non-repairs are recorded. - [ ] Final response shape is recorded. @@ -97,6 +105,7 @@ Completion Gates: | Helper/checker tests | pending | If scripts changed, run focused script tests; otherwise N/A | pending | | Autoreview / review | pending | Run applicable review gate or record N/A for docs-only/source-rule-only repair | pending | | Final lint | pending | Run scoped formatter/lint or record ignored-path/N/A reason | pending | +| Output budget discipline | pending | Verify no unbounded high-volume command output was streamed, or record the accidental output and recovery | pending | | Goal plan complete | yes | Run `node .agents/rules/autogoal/scripts/check-complete.mjs {{PLAN_PATH}}` | pending | Phase / pass table: diff --git a/docs/plans/templates/goal.md b/docs/plans/templates/goal.md index af98face..65c9b3b9 100644 --- a/docs/plans/templates/goal.md +++ b/docs/plans/templates/goal.md @@ -19,6 +19,10 @@ Constraints: Boundaries: - TODO: List allowed files, packages, tools, repos, routes, or data. +Output budget strategy: +- TODO: Record how command/search output will be scoped, capped, counted, or + saved as artifacts before broad exploration. + Blocked condition: - TODO: Name the condition that stops autonomous work. @@ -40,6 +44,7 @@ Start Gates: | `docs/solutions` checked for non-trivial existing-code work | pending | pending | | TDD decision before behavior change or bug fix | pending | pending | | Browser tool decision for browser surface | pending | pending | +| Output budget strategy recorded | pending | pending | Work Checklist: - [ ] Objective, threshold, verification surface, constraints, boundaries, and @@ -52,6 +57,9 @@ Work Checklist: - [ ] High-risk note recorded for public API, runtime, package-boundary, browser behavior, agent-action, or command-contract changes, or marked N/A with reason. +- [ ] Output budget discipline recorded and followed: broad searches are + scoped, capped, counted, or artifacted instead of streamed into goal + context. - [ ] Findings, decisions/tradeoffs, error attempts, and timeline reflect the actual work performed. @@ -71,6 +79,7 @@ Completion Gates: | Autoreview for non-trivial implementation changes | pending | Load `.agents/skills/autoreview/SKILL.md`; use dirty local `--mode local`, branch/PR `--mode branch --base `, or committed slice `--mode commit --commit ` until no accepted/actionable findings, or record N/A for docs-only/planning-only/trivial/no local patch | pending | | PR create or update | pending | Run `check` before PR work | pending | | Final lint | pending | Run `bun lint:fix` or scoped equivalent | pending | +| Output budget discipline | pending | Verify no unbounded high-volume command output was streamed, or record the accidental output and recovery | pending | | Goal plan complete | yes | Run `node .agents/rules/autogoal/scripts/check-complete.mjs {{PLAN_PATH}}` | pending | Phase / pass table: diff --git a/docs/plans/templates/major-task.md b/docs/plans/templates/major-task.md index f4517e7d..b4ed2ba4 100644 --- a/docs/plans/templates/major-task.md +++ b/docs/plans/templates/major-task.md @@ -51,6 +51,10 @@ Boundaries: - Tracker sync: TODO. - Non-goals: TODO. +Output budget strategy: +- TODO: Record how command/search output will be scoped, capped, counted, or + saved as artifacts before broad exploration. + Blocked condition: - TODO: Name the missing source, benchmark, access, design decision, external evidence, or user judgment that stops autonomous major-task work. @@ -93,6 +97,7 @@ Start Gates: | Implementation expectation recorded | pending | pending | | Workspace authority selected | pending | pending | | Branch / PR expectation decided | pending | pending | +| Output budget strategy recorded | pending | pending | Work Checklist: - [ ] Objective includes outcome, completion threshold, verification surface, @@ -115,6 +120,9 @@ Work Checklist: package/API, or agent-native surfaces as needed. - [ ] Workspace authority recorded: every proof command names the cwd/tool that owns the analyzed or changed behavior. +- [ ] Output budget discipline recorded and followed: broad searches are + scoped, capped, counted, or artifacted instead of streamed into goal + context. - [ ] Accepted/actionable review findings are fixed or explicitly rejected with evidence. @@ -131,6 +139,7 @@ Completion Gates: | Implementation gates | pending | If code changed, close primary-template and touched-surface gates; otherwise N/A | pending | | Final handoff contract | pending | Record recommendation, evidence, caveats, residual risk, and next owner | pending | | Final lint | pending | Run `bun lint:fix` or scoped equivalent when files changed | pending | +| Output budget discipline | pending | Verify no unbounded high-volume command output was streamed, or record the accidental output and recovery | pending | | Goal plan complete | yes | Run `node .agents/rules/autogoal/scripts/check-complete.mjs {{PLAN_PATH}}` | pending | Phase / pass table: diff --git a/docs/plans/templates/task.md b/docs/plans/templates/task.md index da75b062..b319f358 100644 --- a/docs/plans/templates/task.md +++ b/docs/plans/templates/task.md @@ -46,6 +46,10 @@ Boundaries: - Tracker sync: TODO. - Non-goals: TODO. +Output budget strategy: +- TODO: Record how command/search output will be scoped, capped, counted, or + saved as artifacts before broad exploration. + Blocked condition: - TODO: Name the missing source context, transcript, repro, access, command, or user decision that stops autonomous work. @@ -89,6 +93,7 @@ Start Gates: | Commit / PR expectation decision | pending | pending | | Task-style PR body decision | pending | pending | | Tracker sync expectation decision | pending | pending | +| Output budget strategy recorded | pending | pending | Work Checklist: - [ ] Objective includes outcome, completion threshold, verification surface, @@ -115,6 +120,9 @@ Work Checklist: reinstall/rerun evidence or N/A with reason. - [ ] Workspace authority recorded: every proof command names the cwd/tool that owns the changed behavior. +- [ ] Output budget discipline recorded and followed: broad searches are + scoped, capped, counted, or artifacted instead of streamed into goal + context. - [ ] High-risk note recorded for public API, runtime, package-boundary, browser behavior, agent-action, or command-contract changes, or marked N/A with reason. @@ -151,6 +159,7 @@ Completion Gates: | Tracker sync-back | pending | Post concise issue/Linear sync after PR exists, or record N/A/blocker | pending | | Final handoff contract | pending | Fill the final handoff fields below with exact PR/issue/confidence/tests/browser/outcome/caveats/design/verification content or N/A reason | pending | | Final lint | pending | Run `bun lint:fix` or scoped equivalent | pending | +| Output budget discipline | pending | Verify no unbounded high-volume command output was streamed, or record the accidental output and recovery | pending | | Goal plan complete | yes | Run `node .agents/rules/autogoal/scripts/check-complete.mjs {{PLAN_PATH}}` | pending | Phase / pass table: diff --git a/packages/kitcn/skills/kitcn/references/features/auth.md b/packages/kitcn/skills/kitcn/references/features/auth.md index fd8ca7cb..0ee7e568 100644 --- a/packages/kitcn/skills/kitcn/references/features/auth.md +++ b/packages/kitcn/skills/kitcn/references/features/auth.md @@ -326,6 +326,15 @@ const signUp = useMutation(useSignUpMutationOptions({ onSuccess: () => router.pu signUp.mutate({ callbackURL: window.location.origin, email, name, password }); ``` +**Plugin sign-in methods** (requires the matching Better Auth client plugin): +```ts +const signIn = useMutation(useSignInMutationOptions({ + signInMethod: 'username', + onSuccess: () => router.push('/'), +})); +signIn.mutate({ callbackURL: window.location.origin, password, username }); +``` + ### Sign Out ```ts diff --git a/packages/kitcn/src/react/auth-mutations.test.tsx b/packages/kitcn/src/react/auth-mutations.test.tsx index 665a5d5f..ca86b591 100644 --- a/packages/kitcn/src/react/auth-mutations.test.tsx +++ b/packages/kitcn/src/react/auth-mutations.test.tsx @@ -212,6 +212,100 @@ describe('createAuthMutations', () => { expect(resetAuthQueries).toHaveBeenCalledTimes(1); }); + test('signIn(username): calls the requested sign-in method', async () => { + const resetAuthQueries = mock(() => {}); + useConvexQueryClientSpy = spyOn( + contextModule, + 'useConvexQueryClient' + ).mockReturnValue({ resetAuthQueries } as any); + + const authClient = { + signOut: mock(async () => ({})), + signIn: { + social: mock(async () => ({})), + email: mock(async () => ({})), + username: mock(async (args: unknown) => ({ + args, + token: 'returned-username-token', + })), + }, + signUp: { email: mock(async () => ({})) }, + }; + + const { useSignInMutationOptions } = createAuthMutations(authClient as any); + + const wrapper = makeWrapper({ token: null }); + + const { result } = renderHook( + () => ({ + store: useAuthStore(), + opts: useSignInMutationOptions({ signInMethod: 'username' }), + }), + { wrapper } + ); + + await act(async () => { + const res = await result.current.opts.mutationFn?.( + { + password: 'pw', + username: 'ada', + }, + makeMutationCtx() + ); + expect(res).toMatchObject({ token: 'returned-username-token' }); + }); + + expect(result.current.store.get('token')).toBe('returned-username-token'); + expect(result.current.store.get('isAuthenticated')).toBe(true); + expect(authClient.signIn.username).toHaveBeenCalledTimes(1); + expect(authClient.signIn.username).toHaveBeenCalledWith({ + password: 'pw', + username: 'ada', + fetchOptions: { + disableSignal: true, + }, + }); + expect(authClient.signIn.email).not.toHaveBeenCalled(); + expect(resetAuthQueries).toHaveBeenCalledTimes(1); + }); + + test('signIn(custom): throws when the sign-in method is missing', async () => { + useConvexQueryClientSpy = spyOn( + contextModule, + 'useConvexQueryClient' + ).mockReturnValue(null as any); + + const authClient = { + signOut: mock(async () => ({})), + signIn: { + social: mock(async () => ({})), + email: mock(async () => ({})), + }, + signUp: { email: mock(async () => ({})) }, + }; + + const { useSignInMutationOptions } = createAuthMutations(authClient as any); + + const wrapper = makeWrapper({ token: null }); + + const { result } = renderHook( + () => ({ + store: useAuthStore(), + opts: useSignInMutationOptions({ signInMethod: 'username' }), + }), + { wrapper } + ); + + await act(async () => { + await expect( + result.current.opts.mutationFn?.( + { password: 'pw', username: 'ada' }, + makeMutationCtx() + ) + ).rejects.toThrow('Auth client does not expose signIn.username'); + }); + }); + test('signUp(email): seeds the auth store from a returned token', async () => { const resetAuthQueries = mock(() => {}); useConvexQueryClientSpy = spyOn( diff --git a/packages/kitcn/src/react/auth-mutations.ts b/packages/kitcn/src/react/auth-mutations.ts index dd799464..bbdc2b09 100644 --- a/packages/kitcn/src/react/auth-mutations.ts +++ b/packages/kitcn/src/react/auth-mutations.ts @@ -31,6 +31,15 @@ type MutationOptionsHook = ( > ) => UseMutationOptions; +type SignInMutationOptionsHook = ( + options?: Omit< + UseMutationOptions, + 'mutationFn' + > & { + signInMethod?: string; + } +) => UseMutationOptions; + /** Poll until JWT token exists (auth complete) (max 5s) */ const waitForAuth = async ( store: AuthStore, @@ -153,8 +162,9 @@ type AuthClient = { signOut?: AnyAuthFn; signIn?: { anonymous?: AnyAuthFn; - social?: AnyAuthFn; email?: AnyAuthFn; + social?: AnyAuthFn; + [method: string]: AnyAuthFn | undefined; }; signUp?: { email?: AnyAuthFn; @@ -251,7 +261,7 @@ type AuthMutationsResult = { MutationArgsWithFetchOptions | void >; useSignInSocialMutationOptions: MutationOptionsHook; - useSignInMutationOptions: MutationOptionsHook; + useSignInMutationOptions: SignInMutationOptionsHook; useSignUpMutationOptions: MutationOptionsHook; }; @@ -318,16 +328,17 @@ export function createAuthMutations( const useSignInMutationOptions = ((options) => { const authStoreApi = useAuthStore(); const convexQueryClient = useConvexQueryClient(); + const { signInMethod = 'email', ...mutationOptions } = options ?? {}; return { - ...options, + ...mutationOptions, mutationFn: async (args: unknown) => { - const signInEmail = authClient.signIn?.email; - if (typeof signInEmail !== 'function') { - throw new Error('Auth client does not expose signIn.email'); + const signIn = authClient.signIn?.[signInMethod]; + if (typeof signIn !== 'function') { + throw new Error(`Auth client does not expose signIn.${signInMethod}`); } const res = (await callAuthMethod( - signInEmail, + signIn, withDisabledSessionSignal(args) )) as AuthResponse; if (res?.error) { diff --git a/packages/kitcn/src/react/auth-mutations.types.test.ts b/packages/kitcn/src/react/auth-mutations.types.test.ts index 9b9bb15f..d636f249 100644 --- a/packages/kitcn/src/react/auth-mutations.types.test.ts +++ b/packages/kitcn/src/react/auth-mutations.types.test.ts @@ -23,15 +23,17 @@ describe('createAuthMutations types', () => { fs.writeFileSync( fixtureFile, `import { createAuthClient } from "better-auth/react"; +import { usernameClient } from "better-auth/client/plugins"; import { convexClient } from "../../packages/kitcn/src/auth-client/index"; import { createAuthMutations } from "../../packages/kitcn/src/react/auth-mutations"; const authClient = createAuthClient({ baseURL: "http://localhost:3000", - plugins: [convexClient()], + plugins: [usernameClient(), convexClient()], }); -createAuthMutations(authClient); +const { useSignInMutationOptions } = createAuthMutations(authClient); +useSignInMutationOptions({ signInMethod: "username" }); ` ); diff --git a/packages/kitcn/src/solid/auth-mutations.ts b/packages/kitcn/src/solid/auth-mutations.ts index 1f6c453a..b9e2d75c 100644 --- a/packages/kitcn/src/solid/auth-mutations.ts +++ b/packages/kitcn/src/solid/auth-mutations.ts @@ -21,6 +21,54 @@ type MutationOptionsHook = ( > ) => SolidMutationOptions; +type SignInMethod = Extract; + +type EmailSignInMutationOptions = Omit< + SolidMutationOptions< + Awaited>, + DefaultError, + Parameters[0] + >, + 'mutationFn' +> & { + signInMethod?: 'email'; +}; + +type CustomSignInMutationOptions< + T extends AuthClient, + TMethod extends SignInMethod, +> = Omit< + SolidMutationOptions< + Awaited>, + DefaultError, + Parameters[0] + >, + 'mutationFn' +> & { + signInMethod: TMethod; +}; + +type SignInMutationOptionsHook = { + ( + options?: EmailSignInMutationOptions + ): SolidMutationOptions< + Awaited>, + DefaultError, + Parameters[0] + >; + , 'email'>>( + options: CustomSignInMutationOptions + ): SolidMutationOptions< + Awaited>, + DefaultError, + Parameters[0] + >; +}; + +type SignInOptions = + | EmailSignInMutationOptions + | CustomSignInMutationOptions, 'email'>>; + /** Poll until JWT token exists (auth complete) (max 5s) */ const waitForAuth = async ( store: AuthStore, @@ -82,9 +130,9 @@ type AnyFn = (...args: any[]) => Promise; type AuthClient = { signOut: AnyFn; - signIn: { - social: AnyFn; + signIn: Record & { email: AnyFn; + social: AnyFn; }; signUp: { email: AnyFn; @@ -101,10 +149,7 @@ type AuthMutationsResult = { Awaited>, Parameters[0] >; - useSignInMutationOptions: MutationOptionsHook< - Awaited>, - Parameters[0] - >; + useSignInMutationOptions: SignInMutationOptionsHook; useSignUpMutationOptions: MutationOptionsHook< Awaited>, Parameters[0] @@ -176,13 +221,19 @@ export function createAuthMutations( }; }) as AuthMutationsResult['useSignInSocialMutationOptions']; - const useSignInMutationOptions = ((options) => { + const useSignInMutationOptions = ((options?: SignInOptions) => { const authStoreApi = useAuthStore(); + const { signInMethod = 'email', ...mutationOptions } = (options ?? + {}) as SignInOptions & { signInMethod?: string }; return { - ...options, + ...mutationOptions, mutationFn: async (args: Parameters[0]) => { - const res = await authClient.signIn.email(args); + const signIn = authClient.signIn[signInMethod]; + if (typeof signIn !== 'function') { + throw new Error(`Auth client does not expose signIn.${signInMethod}`); + } + const res = await signIn(args); if (res?.error) { throw new AuthMutationError(res.error); } diff --git a/packages/kitcn/src/solid/auth-mutations.types.vitest.ts b/packages/kitcn/src/solid/auth-mutations.types.vitest.ts new file mode 100644 index 00000000..acc12d12 --- /dev/null +++ b/packages/kitcn/src/solid/auth-mutations.types.vitest.ts @@ -0,0 +1,59 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import ts from 'typescript'; + +const formatDiagnostics = (diagnostics: readonly ts.Diagnostic[]) => + ts.formatDiagnosticsWithColorAndContext(diagnostics, { + getCanonicalFileName: (fileName) => fileName, + getCurrentDirectory: () => process.cwd(), + getNewLine: () => '\n', + }); + +describe('createAuthMutations solid types', () => { + test('accepts a username sign-in method from Better Auth plugins', () => { + const rootDir = process.cwd(); + const tmpRoot = path.join(rootDir, 'tmp'); + fs.mkdirSync(tmpRoot, { recursive: true }); + const fixtureDir = fs.mkdtempSync( + path.join(tmpRoot, 'kitcn-solid-auth-mutations-types-') + ); + const fixtureFile = path.join(fixtureDir, 'repro.ts'); + + try { + fs.writeFileSync( + fixtureFile, + `import { createAuthClient } from "better-auth/solid"; +import { usernameClient } from "better-auth/client/plugins"; +import { convexClient } from "../../packages/kitcn/src/auth-client/index"; +import { createAuthMutations } from "../../packages/kitcn/src/solid/auth-mutations"; + +const authClient = createAuthClient({ + baseURL: "http://localhost:3000", + plugins: [usernameClient(), convexClient()], +}); + +const { useSignInMutationOptions } = createAuthMutations(authClient); +useSignInMutationOptions({ signInMethod: "username" }); +` + ); + + const program = ts.createProgram([fixtureFile], { + allowImportingTsExtensions: true, + jsx: ts.JsxEmit.ReactJSX, + module: ts.ModuleKind.ESNext, + moduleResolution: ts.ModuleResolutionKind.Bundler, + noEmit: true, + skipLibCheck: true, + strict: true, + strictFunctionTypes: true, + target: ts.ScriptTarget.ES2022, + types: ['bun-types'], + }); + const diagnostics = ts.getPreEmitDiagnostics(program); + + expect(formatDiagnostics(diagnostics)).toBe(''); + } finally { + fs.rmSync(fixtureDir, { force: true, recursive: true }); + } + }); +}); diff --git a/packages/kitcn/src/solid/auth-mutations.vitest.tsx b/packages/kitcn/src/solid/auth-mutations.vitest.tsx index bb000b44..4df67112 100644 --- a/packages/kitcn/src/solid/auth-mutations.vitest.tsx +++ b/packages/kitcn/src/solid/auth-mutations.vitest.tsx @@ -196,6 +196,92 @@ describe('createAuthMutations', () => { expect(authClient.signIn.email).toHaveBeenCalledTimes(1); }); + test('signIn(username): calls the requested sign-in method', async () => { + useConvexQueryClientSpy = vi + .spyOn(contextModule, 'useConvexQueryClient') + .mockReturnValue(null as any); + + const authClient = { + signOut: vi.fn(async () => ({})), + signIn: { + social: vi.fn(async () => ({})), + email: vi.fn(async () => ({})), + username: vi.fn(async (args: unknown) => ({ + args, + token: 'returned-username-token', + })), + }, + signUp: { + email: vi.fn(async () => ({})), + }, + }; + + const { useSignInMutationOptions } = createAuthMutations(authClient as any); + + const wrapper = makeWrapper({ token: null }); + + const { result } = renderHook( + () => ({ + store: useAuthStore(), + opts: useSignInMutationOptions({ signInMethod: 'username' } as any), + }), + { wrapper } + ); + + const res = await result.opts.mutationFn?.( + { + password: 'pw', + username: 'ada', + }, + makeMutationCtx() + ); + expect(res).toMatchObject({ token: 'returned-username-token' }); + + expect(result.store.get('token')).toBe('returned-username-token'); + expect(authClient.signIn.username).toHaveBeenCalledTimes(1); + expect(authClient.signIn.username).toHaveBeenCalledWith({ + password: 'pw', + username: 'ada', + }); + expect(authClient.signIn.email).not.toHaveBeenCalled(); + }); + + test('signIn(custom): throws when the sign-in method is missing', async () => { + useConvexQueryClientSpy = vi + .spyOn(contextModule, 'useConvexQueryClient') + .mockReturnValue(null as any); + + const authClient = { + signOut: vi.fn(async () => ({})), + signIn: { + social: vi.fn(async () => ({})), + email: vi.fn(async () => ({})), + }, + signUp: { + email: vi.fn(async () => ({})), + }, + }; + + const { useSignInMutationOptions } = createAuthMutations(authClient as any); + + const wrapper = makeWrapper({ token: null }); + + const { result } = renderHook( + () => ({ + store: useAuthStore(), + opts: useSignInMutationOptions({ signInMethod: 'username' } as any), + }), + { wrapper } + ); + + await expect( + result.opts.mutationFn?.( + { password: 'pw', username: 'ada' }, + makeMutationCtx() + ) + ).rejects.toThrow('Auth client does not expose signIn.username'); + }); + test('signUp(email): seeds the auth store from a returned token', async () => { useConvexQueryClientSpy = vi .spyOn(contextModule, 'useConvexQueryClient') diff --git a/www/content/docs/auth/client.mdx b/www/content/docs/auth/client.mdx index 46048c7e..e87d24e7 100644 --- a/www/content/docs/auth/client.mdx +++ b/www/content/docs/auth/client.mdx @@ -184,6 +184,37 @@ function EmailLoginForm() { Unlike OAuth (which redirects server-side), email/password auth requires a client-side redirect via `onSuccess`. +### Plugin Sign-In Methods + +Better Auth client plugins can add sign-in methods under `authClient.signIn`. +Set `signInMethod` when the mutation should call one of those methods: + +```tsx title="src/components/username-login-form.tsx" showLineNumbers {7-10,13-18} +'use client'; + +import { useMutation } from '@tanstack/react-query'; +import { useRouter } from 'next/navigation'; +import { useSignInMutationOptions } from '@/lib/convex/auth-client'; + +function UsernameLoginForm() { + const router = useRouter(); + const signIn = useMutation( + useSignInMutationOptions({ + signInMethod: 'username', + onSuccess: () => router.push('/'), + }) + ); + + const handleSubmit = (username: string, password: string) => { + signIn.mutate({ + callbackURL: window.location.origin, + password, + username, + }); + }; +} +``` + ## Sign Out ```tsx title="src/components/logout-button.tsx" showLineNumbers {6,8-12,15} From 9cc68440cd54f2daf2335c13fcd45848f3cfb9c7 Mon Sep 17 00:00:00 2001 From: zbeyens Date: Wed, 27 May 2026 11:41:32 +0200 Subject: [PATCH 2/2] fix: restore task pr body style --- .agents/rules/task.mdc | 28 ++- .agents/skills/task/SKILL.md | 28 ++- .../2026-05-27-repair-task-pr-body-style.md | 233 ++++++++++++++++++ docs/plans/templates/task.md | 26 +- 4 files changed, 285 insertions(+), 30 deletions(-) create mode 100644 docs/plans/2026-05-27-repair-task-pr-body-style.md diff --git a/.agents/rules/task.mdc b/.agents/rules/task.mdc index e4d7078c..38e4a7d3 100644 --- a/.agents/rules/task.mdc +++ b/.agents/rules/task.mdc @@ -288,20 +288,28 @@ task final handoff. Do not use a generic `Summary` / `Verification` PR body, an adaptive prose body from `git-commit-push-pr`, or a generated badge footer unless the caller or repo template explicitly asks for it. -Use this order: +Use the accepted task PR format from PR #270. The shape is not optional: 1. Preserve any existing `` block. If a changeset is part of the diff and repo policy expects auto release, include that block. -2. Issue, tracker, or fix line when applicable. Never include a line that links - to the current PR itself; the current PR URL belongs in the final response, - not in its own description. -3. Confidence line. -4. Reproduced / Verified table with test and browser columns. -5. `Outcome`, `Caveat`, `Design`, and `Verified` sections. +2. Use an emoji-prefixed issue/tracker/fix line, for example + `πŸ› Fixes #123` or `πŸ› Fixes βž– N/A`. Never include a line that links to the + current PR itself; the current PR URL belongs in the final response, not in + its own description. +3. Use an emoji confidence line, for example `🟒 95-100% confidence`. +4. Use this exact table header: + `| Phase | πŸ§ͺ Tests | 🌐 Browser |` +5. Use `Reproduced` and `Verified` rows. Mark passing proof with `🟒`, repro or + failing proof with `πŸ”΄`, and non-applicable browser/test cells with `βž– N/A`. +6. Use bold emoji section headings exactly in this family: + `**βœ… Outcome**`, `**⚠️ Caveat**`, `**πŸ—οΈ Design**`, and + `**πŸ§ͺ Verified**`. The body should tell QA/reviewers what was fixed, how it was reproduced, how it -was verified, and why the chosen ownership boundary is right. After editing, -verify it with `gh pr view --json body` before final handoff. +was verified, and why the chosen ownership boundary is right. It must not use +plain `Fix:`, plain `Confidence:`, `## Outcome`, `## Verified`, or a generic +`Summary` / `Verification` shape for task-run PRs. After editing, verify it +with `gh pr view --json body` before final handoff. ## Success Criteria @@ -320,6 +328,6 @@ verify it with `gh pr view --json body` before final handoff. - Verified code-changing work was committed and PR'd, or the user explicitly declined that path, the work had no local patch, or a real blocker was recorded. -- PR descriptions created by task runs used the task-style final handoff body +- PR descriptions created by task runs used the PR #270 emoji task-style body and were verified with `gh pr view --json body`. - Final handoff matched the task type and any task-template gate evidence. diff --git a/.agents/skills/task/SKILL.md b/.agents/skills/task/SKILL.md index 6e33bc6b..d3a4a670 100644 --- a/.agents/skills/task/SKILL.md +++ b/.agents/skills/task/SKILL.md @@ -292,20 +292,28 @@ task final handoff. Do not use a generic `Summary` / `Verification` PR body, an adaptive prose body from `git-commit-push-pr`, or a generated badge footer unless the caller or repo template explicitly asks for it. -Use this order: +Use the accepted task PR format from PR #270. The shape is not optional: 1. Preserve any existing `` block. If a changeset is part of the diff and repo policy expects auto release, include that block. -2. Issue, tracker, or fix line when applicable. Never include a line that links - to the current PR itself; the current PR URL belongs in the final response, - not in its own description. -3. Confidence line. -4. Reproduced / Verified table with test and browser columns. -5. `Outcome`, `Caveat`, `Design`, and `Verified` sections. +2. Use an emoji-prefixed issue/tracker/fix line, for example + `πŸ› Fixes #123` or `πŸ› Fixes βž– N/A`. Never include a line that links to the + current PR itself; the current PR URL belongs in the final response, not in + its own description. +3. Use an emoji confidence line, for example `🟒 95-100% confidence`. +4. Use this exact table header: + `| Phase | πŸ§ͺ Tests | 🌐 Browser |` +5. Use `Reproduced` and `Verified` rows. Mark passing proof with `🟒`, repro or + failing proof with `πŸ”΄`, and non-applicable browser/test cells with `βž– N/A`. +6. Use bold emoji section headings exactly in this family: + `**βœ… Outcome**`, `**⚠️ Caveat**`, `**πŸ—οΈ Design**`, and + `**πŸ§ͺ Verified**`. The body should tell QA/reviewers what was fixed, how it was reproduced, how it -was verified, and why the chosen ownership boundary is right. After editing, -verify it with `gh pr view --json body` before final handoff. +was verified, and why the chosen ownership boundary is right. It must not use +plain `Fix:`, plain `Confidence:`, `## Outcome`, `## Verified`, or a generic +`Summary` / `Verification` shape for task-run PRs. After editing, verify it +with `gh pr view --json body` before final handoff. ## Success Criteria @@ -324,6 +332,6 @@ verify it with `gh pr view --json body` before final handoff. - Verified code-changing work was committed and PR'd, or the user explicitly declined that path, the work had no local patch, or a real blocker was recorded. -- PR descriptions created by task runs used the task-style final handoff body +- PR descriptions created by task runs used the PR #270 emoji task-style body and were verified with `gh pr view --json body`. - Final handoff matched the task type and any task-template gate evidence. diff --git a/docs/plans/2026-05-27-repair-task-pr-body-style.md b/docs/plans/2026-05-27-repair-task-pr-body-style.md new file mode 100644 index 00000000..0c5524c4 --- /dev/null +++ b/docs/plans/2026-05-27-repair-task-pr-body-style.md @@ -0,0 +1,233 @@ +# repair task pr body style + +Objective: +Repair the task workflow PR-body style regression so future `task` runs use the +accepted PR #270 emoji format, and prove it by comparing the current source +against the April 2026 task rule and PR #270 body. + +Goal plan: +docs/plans/2026-05-27-repair-task-pr-body-style.md + +Template: +docs/plans/templates/goal-repair.md + +Primary template: +docs/plans/templates/goal-repair.md + +Applied packs: +- none + +Expectation: +- user expectation: `task` PR bodies must look like PR #270, not the plain + generic body used on PR #275. +- observed miss: current `task.mdc` and `docs/plans/templates/task.md` required + task ownership of PR bodies but described a plain format, so the generated PR + body could use `Fix:`, `Confidence:`, and `## Outcome` headings. +- owning skill/template/helper: `.agents/rules/task.mdc` and + `docs/plans/templates/task.md`; generated `.agents/skills/task/SKILL.md` + must be synced through `bun install`. +- repair classification: derived task rule plus task goal template repair. + +Completion threshold: +- `.agents/rules/task.mdc` explicitly names PR #270 and the emoji task-style + body markers. +- `docs/plans/templates/task.md` requires the same PR #270 format in the task + PR body gate and contract. +- `.agents/skills/task/SKILL.md` is regenerated from the source rule. +- PR #275 body is corrected to the PR #270 emoji format and verified with + `gh pr view`. +- Lint, source audits, generated sync audit, and `bun check` pass. +- `node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-27-repair-task-pr-body-style.md` + passes. + +Verification surface: +- Source comparison: `gh pr view 270`, `git rev-list --before='2026-04-27 + 23:59:59'`, `git show :.agents/rules/task.mdc`, and current source + reads. +- Source audit: `rg` for `PR #270`, `πŸ› Fixes`, `🟒 95-100% confidence`, the + `Phase | πŸ§ͺ Tests | 🌐 Browser` table, and bold emoji section headings across + task rule, generated skill, and task template. +- Generated sync: diff of the `Task-Style PR Body` section between + `.agents/rules/task.mdc` and `.agents/skills/task/SKILL.md`. +- PR proof: `gh pr view 275 --json body,url,headRefName,headRefOid`. +- Repo proof: `bun lint:fix` and `bun check`. + +Constraints: +- Repair one expectation narrowly. +- Patch source-of-truth files, not generated skill mirrors by hand. +- Do not weaken evidence safety or completion gates. +- Do not broaden the repair to unrelated skills/templates. +- Preserve the auth sign-in work already in PR #275. + +Boundaries: +- Source of truth: latest user correction, PR #270 body, April 2026 + `.agents/rules/task.mdc`, current task rule/template, and PR #275 body. +- Allowed edit scope: `.agents/rules/task.mdc`, generated + `.agents/skills/task/SKILL.md` through sync, `docs/plans/templates/task.md`, + this repair plan, and PR #275 body. +- Derived skill scope: `task`; `autogoal` only owns repair lifecycle. +- Non-goals: rewrite generic git PR helpers, change package runtime code, + change unrelated templates, or alter the auth feature design. + +Output budget strategy: +- Use focused file reads and `rg` audits only. +- Capture high-volume `bun check` output under ignored `tmp/verification`. + +Blocked condition: +- Block only if PR #270 body, April task history, generated skill sync, PR #275 + body update, or `bun check` cannot be accessed/run after a real attempt. No + blocker remained. + +Repair state: +- repair_type: task PR body style contract +- current_phase: closeout +- current_phase_status: complete +- next_phase: final response +- goal_status: active until final goal completion. + +Current verdict: +- verdict: regression repaired +- confidence: high +- next owner: reviewer +- reason: task rule/template now encode the concrete PR #270 body format, and + PR #275 has been rewritten to that format. + +Completion rule: +- Do not call `update_goal(status: complete)` until this plan passes + `check-complete.mjs`, PR #275 body remains verified, and the branch is pushed. + +Start Gates: +| Gate | Applies | Evidence | +|------|---------|----------| +| Expectation restated | yes | User said PR #270 is correct and current PR style is wrong. | +| Active goal checked | yes | `get_goal` returned no active goal; a repair goal was created. | +| Named plan or skill read | yes | Read `.agents/rules/task.mdc`, `docs/plans/templates/task.md`, and PR #270. | +| Owning source selected | yes | Source owner is `.agents/rules/task.mdc`; template owner is `docs/plans/templates/task.md`. | +| Repair classification selected | yes | Derived task rule/template repair. | +| Safety conflict checked | yes | No conflict: this strengthens body format proof and keeps existing evidence gates. | +| Output budget strategy recorded | yes | This plan records focused reads and ignored log capture. | + +Work Checklist: +- [x] Expectation and observed miss are stated with source evidence. +- [x] Primary owner selected: runtime plan, template, skill rule, or + helper/checker. +- [x] Secondary owners are justified or marked N/A. +- [x] Patch touches source-of-truth files only. +- [x] Derived skill vs generic `autogoal` ownership decision is recorded. +- [x] Output budget discipline recorded and followed: broad searches are + scoped, capped, counted, or artifacted instead of streamed into goal + context. +- [x] Deliberate non-repairs are recorded. +- [x] Final response shape is recorded. + +Completion Gates: +| Gate | Applies | Required action | Evidence | +|------|---------|-----------------|----------| +| Source owner patched | yes | Patch the selected source owner or record runtime-plan-only repair | `.agents/rules/task.mdc` now names PR #270 and exact emoji body markers. | +| Generated skill sync | yes | If `.agents/rules/**` changed, run `bun install` and verify generated `SKILL.md` sync | `bun install` ran; source/generated `Task-Style PR Body` section diff produced no output. | +| Template smoke | yes | Instantiate the repaired template or inspect it directly when a smoke plan would create noise | Direct template inspection shows PR #270 gate and contract in `docs/plans/templates/task.md`. | +| Incomplete-plan guard | N/A: checker behavior unchanged | Verify unfinished generated plan still fails or record N/A | No checker/script logic changed. | +| Completed-plan representability | yes | Verify repaired expectation can be recorded in a completed plan | This completed repair plan records the PR #270 expectation without template edits. | +| Helper/checker tests | N/A: no helper/checker changed | Run focused script tests or record N/A | No script changed. | +| Autoreview / review | N/A: source-rule-only repair with full source audit | Run applicable review gate or record N/A | Manual source audit plus `bun check`; no app code behavior changed. | +| Final lint | yes | Run scoped formatter/lint or record ignored-path/N/A reason | `bun lint:fix` passed. | +| Output budget discipline | yes | Verify no unbounded high-volume command output was streamed | `bun check` output captured to ignored log; chat only received final tail. | +| Goal plan complete | yes | Run `node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-27-repair-task-pr-body-style.md` | `check-complete.mjs` passed. | + +Phase / pass table: +| Phase | Status | Evidence | Next | +|-------|--------|----------|------| +| Intake | complete | Read user correction, PR #270, current task rule/template, and April task rule. | target selection | +| Target selection | complete | Selected task rule/template, not generic autogoal or git helper. | patch | +| Patch | complete | Patched `.agents/rules/task.mdc` and `docs/plans/templates/task.md`; synced generated task skill. | verification | +| Verification | complete | Source audit, generated sync diff, PR body audit, lint, and `bun check` passed. | closeout | +| Closeout | complete | PR #275 body corrected; plan ready for checker, commit, push, final response. | final response | + +Findings: +- PR #270 uses the expected body: auto-release block, `πŸ› Fixes ...`, `🟒 + 95-100% confidence`, `Phase | πŸ§ͺ Tests | 🌐 Browser`, and bold emoji + sections. +- Current task rule/template had regressed to describing the body generically, + which allowed the wrong plain PR #275 style. +- April 2026 task history did not contain the newer concrete PR-body gate, so + the repair needs to keep the modern gate but restore the accepted visual + style from PR #270. + +Decisions and tradeoffs: +- Patch `task`, not generic `autogoal`: this is a task-run PR-body contract, not + a universal goal lifecycle rule. +- Keep `git-commit-push-pr` as transport only; `task` owns PR body content. +- Use PR #270 as the concrete source of truth instead of inventing another + β€œcleaner” body format. + +Repair patch notes: +- `.agents/rules/task.mdc` now bans plain `Fix:`, plain `Confidence:`, + `## Outcome`, `## Verified`, and generic Summary/Verification bodies for + task-run PRs. +- `docs/plans/templates/task.md` now requires the PR #270 body markers in the + task-style PR body completion gate and contract. +- `.agents/skills/task/SKILL.md` was regenerated by `bun install`. +- PR #275 body was rewritten to the PR #270 emoji format. + +Deliberate non-repairs: +- Did not edit generic git PR helpers; non-task PR workflows can stay adaptive. +- Did not change package runtime or auth implementation. +- Did not add checker/script enforcement; the source/template contract is now + concrete enough and this repair is narrow. + +Error attempts: +| Error / failed attempt | Count | Next different move | Resolution | +|------------------------|-------|---------------------|------------| +| None | 0 | N/A | N/A | + +Verification evidence: +- `gh pr view 270 --json title,body,headRefName,baseRefName,url --jq ...` + showed the accepted PR #270 body format. +- `git rev-list -n 1 --before='2026-04-27 23:59:59' HEAD -- .agents/rules/task.mdc` + selected April commit `3a95ffbf86872dbd29dbe806c1a48a10189ce611`. +- `git show :.agents/rules/task.mdc` was inspected for last-month task + workflow shape. +- `rg -n 'PR #270|πŸ› Fixes|🟒 95-100% confidence|Phase \| πŸ§ͺ Tests \| 🌐 Browser|βœ… Outcome|⚠️ Caveat|πŸ—οΈ Design|πŸ§ͺ Verified' .agents/rules/task.mdc .agents/skills/task/SKILL.md docs/plans/templates/task.md` + found the repaired body markers in all owners. +- Source/generated `Task-Style PR Body` section diff produced no output. +- `bun install` passed. +- `bun lint:fix` passed. +- `bun check` exited 0; exit code recorded in + `tmp/verification/bun-check-task-pr-style.exit`. +- `gh pr view 275 --json body,url,headRefName,headRefOid` verified PR #275 body + uses the PR #270 emoji format. +- `node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-27-repair-task-pr-body-style.md` + passed. + +Final repair handoff: +- Expectation: PR bodies created by `task` must use the accepted PR #270 emoji + task-style format. +- Repaired owner: `.agents/rules/task.mdc` and `docs/plans/templates/task.md`; + generated `.agents/skills/task/SKILL.md` synced. +- Files changed: task rule, generated task skill, task template, repair plan. +- Verification: source audit, generated sync diff, PR body audit, `bun + lint:fix`, and `bun check`. +- Caveat: PR #275 now also includes this workflow repair because the wrong body + was caught on that PR. + +Timeline: +- 2026-05-27T09:20:08.824Z Goal repair plan created. +- Fetched PR #270 body and identified the expected emoji style. +- Compared current task rule/template with April 2026 task rule. +- Patched task source rule and task goal template. +- Ran `bun install` to sync generated task skill. +- Audited repaired body markers across source, generated skill, and template. +- Ran `bun lint:fix` and full `bun check`. +- Rewrote PR #275 body to PR #270 style and verified with `gh pr view`. + +Reboot status: +| Question | Answer | +|----------|--------| +| Where am I? | Closeout | +| Where am I going? | Run plan checker, commit, push, mark goal complete | +| What is the goal? | Repair task PR-body style regression using PR #270 as source | +| What have I learned? | Yesterday’s repair fixed ownership but not the required visual format | +| What have I done? | Patched rule/template, synced generated skill, verified, and corrected PR #275 body | + +Open risks: +- None. diff --git a/docs/plans/templates/task.md b/docs/plans/templates/task.md index b319f358..370be252 100644 --- a/docs/plans/templates/task.md +++ b/docs/plans/templates/task.md @@ -35,8 +35,8 @@ Constraints: - Verified code changes must be committed and PR'd because the task skill requires that path unless the user explicitly says not to, the work has no local patch, or a real blocker is recorded. -- A PR created by this task must use the task-style PR body contract below, not - a generic summary/body from a git helper skill. +- A PR created by this task must use the PR #270 emoji task-style PR body + contract below, not a generic summary/body from a git helper skill. - Do not add broad ceremony when the task is trivial or docs-only. Boundaries: @@ -112,8 +112,8 @@ Work Checklist: requirements, PR body sync, and issue/Linear sync when applicable. - [ ] Commit/PR handling recorded for code-changing work: commit and PR completed, no local patch, user explicitly declined, or blocker recorded. -- [ ] PR body shape recorded: task-style body used, N/A reason recorded, or - blocker recorded. +- [ ] PR body shape recorded: PR #270 emoji task-style body used, N/A reason + recorded, or blocker recorded. - [ ] Branch handling recorded for code-changing work: dedicated branch used, new branch needed, or N/A with reason. - [ ] Local-env-rot retry policy recorded for any surprising repo-wide failure: @@ -154,7 +154,7 @@ Completion Gates: | Autoreview for non-trivial implementation changes | pending | Load `.agents/skills/autoreview/SKILL.md`; use dirty local `--mode local`, branch/PR `--mode branch --base `, or committed slice `--mode commit --commit ` until no accepted/actionable findings, or record N/A for docs-only/trivial/no local patch | pending | | Commit created | pending | For verified code-changing work, stage the entire current checkout per repo policy and create a commit; N/A only for no local patch, explicit user decline, analytical/blocked/inconclusive work, or recorded external blocker | pending | | PR create or update | pending | For verified code-changing work, run `check`, push, create or update the PR, and sync PR body to the task-style final handoff; N/A only for no local patch, explicit user decline, analytical/blocked/inconclusive work, or recorded external blocker | pending | -| Task-style PR body verified | pending | Verify the PR body with `gh pr view --json body`; it must preserve auto-release blocks when applicable, must not include a current-PR self-link, and must include an issue/tracker/fix line when applicable, confidence, Reproduced/Verified table, Outcome, Caveat, Design, and Verified sections as applicable | pending | +| Task-style PR body verified | pending | Verify the PR body with `gh pr view --json body`; it must preserve auto-release blocks when applicable, must not include a current-PR self-link, and must use the PR #270 emoji format: `πŸ› Fixes ...`, `🟒 95-100% confidence`, `Phase / πŸ§ͺ Tests / 🌐 Browser` table, and bold emoji Outcome/Caveat/Design/Verified sections | pending | | PR proof image hosting | pending | If PR body needs browser proof, replace local image paths with hosted GitHub URLs or record N/A | pending | | Tracker sync-back | pending | Post concise issue/Linear sync after PR exists, or record N/A/blocker | pending | | Final handoff contract | pending | Fill the final handoff fields below with exact PR/issue/confidence/tests/browser/outcome/caveats/design/verification content or N/A reason | pending | @@ -212,14 +212,20 @@ Final handoff contract: Task-style PR body contract: - Preserve any existing `` block. If a changeset is part of the diff and repo policy expects auto release, include that block. -- Use the final handoff fields in this order: issue, tracker, or fix line when - applicable; confidence line; Reproduced / Verified table; Outcome; Caveat; - Design; and Verified. +- Use the accepted PR #270 visual format. The body starts with an emoji + issue/tracker/fix line, for example `πŸ› Fixes #123` or `πŸ› Fixes βž– N/A`, then + an emoji confidence line like `🟒 95-100% confidence`. +- Use this exact table header: `| Phase | πŸ§ͺ Tests | 🌐 Browser |`. +- Use `Reproduced` and `Verified` rows. Mark passing proof with `🟒`, repro or + failing proof with `πŸ”΄`, and non-applicable cells with `βž– N/A`. +- Use bold emoji section headings: `**βœ… Outcome**`, `**⚠️ Caveat**`, + `**πŸ—οΈ Design**`, and `**πŸ§ͺ Verified**`. - Never include a line that links to the current PR itself. The current PR URL belongs in the final response, not in its own description. - Do not replace this with a generic `Summary` / `Verification` PR body, an - adaptive prose body from a git helper skill, or an unrelated generated badge - footer unless the caller or repo template explicitly asks for it. + adaptive prose body from a git helper skill, plain `## Outcome` sections, or + an unrelated generated badge footer unless the caller or repo template + explicitly asks for it. - Proof is `gh pr view --json body` output or a concise source-backed summary of that output.