diff --git a/.changeset/calm-otters-merge.md b/.changeset/calm-otters-merge.md new file mode 100644 index 000000000..f067065bb --- /dev/null +++ b/.changeset/calm-otters-merge.md @@ -0,0 +1,7 @@ +--- +"kitcn": patch +--- + +## Patches + +- Improve generated procedure-name lookups with merge-local entries and stale-state warnings. diff --git a/docs/plans/2026-09-10-fix-crpc-client-error-guards.md b/docs/plans/2026-09-10-fix-crpc-client-error-guards.md index a6b2c7076..4771b8f87 100644 --- a/docs/plans/2026-09-10-fix-crpc-client-error-guards.md +++ b/docs/plans/2026-09-10-fix-crpc-client-error-guards.md @@ -109,17 +109,17 @@ Work Checklist: - [x] Resolve the full-check blocker or record a maintainer disposition. Completion Gates: -| Gate | Result | Evidence | -| --- | --- | --- | -| Focused regression | passed | 36 cRPC tests pass after rebuilding | -| Package build | passed | All four build groups | -| Typechecks | passed | Package and repository root | -| Lint | passed | `biome check && eslint` | -| Code review | recorded | Implementation review reported no actionable findings | -| Release artifact | present | `.changeset/crpc-guards-across-entrypoints.md` | -| Full repository check | passed before final review repair | Exact-head CI run `34914786162` passed in 6m28s; final repaired-head CI pending | -| PR ownership | recorded | #464 | -| PR plan reference | passed | Body names this plan and fetched head contains it with exact PR #464 | +| Gate | Applies | Result | Evidence | +| --- | --- | --- | --- | +| Focused regression | yes | passed | 36 cRPC tests pass after rebuilding | +| Package build | yes | passed | All four build groups | +| Typechecks | yes | passed | Package and repository root | +| Lint | yes | passed | `biome check && eslint` | +| Code review | yes | passed | Local P0/P1 autoreview clean at 0.94; automated final-head review clean | +| Release artifact | yes | present | `.changeset/crpc-guards-across-entrypoints.md` at final head | +| Full repository check | yes | passed | Exact-head CI run `34916336275` passed in 6m38s | +| PR ownership | yes | recorded | #464 | +| PR plan reference | yes | passed | Body names this plan and fetched head contains exact PR #464 | Phase / pass table: | Phase | Status | Evidence | @@ -127,8 +127,8 @@ Phase / pass table: | Reproduction | complete | Built React and Solid tests fail on base `c12407fc` | | Implementation | complete | Validated shape check; shared guard delegation | | Focused verification | complete | cRPC tests, build, typechecks and lint pass | -| Full repository verification | in progress | PR #467 removed the fixture blocker; repaired-head CI pending | -| PR delivery | in progress | #464; exact task evidence and updated-head approval verified | +| Full repository verification | complete | Local `bun check` and exact-head CI passed | +| PR delivery | complete | Receipt `5673217013`; merged as `ac73cc6a` | Verification evidence: Results recorded during implementation on 2026-09-14: @@ -176,3 +176,12 @@ Open risks: - Errors from another JavaScript realm fail `instanceof Error`. The reproduced package-entrypoint failure occurs within one realm. - An unsupported code supplied by bypassing TypeScript is rejected. + +Reboot status: +| Question | Answer | +| --- | --- | +| Where am I? | Complete; PR #464 is merged | +| Where am I going? | Parent autoclosure goal completion | +| What is the goal? | Recognize cRPC client errors across built package entrypoints | +| What have I learned? | Release #468 consumed the earlier living changeset before final merge | +| What have I done? | Passed final proof, resolved feedback, posted receipt, and merged `ac73cc6a` | diff --git a/docs/plans/2026-09-14-fix-next-fixture-eslint-10-compatibility.md b/docs/plans/2026-09-14-fix-next-fixture-eslint-10-compatibility.md index a35ce7493..0450d67de 100644 --- a/docs/plans/2026-09-14-fix-next-fixture-eslint-10-compatibility.md +++ b/docs/plans/2026-09-14-fix-next-fixture-eslint-10-compatibility.md @@ -306,7 +306,7 @@ Phase / pass table: | Implementation | complete | package overlay and runtime cleanup owners fixed with tests | verification | | Verification | complete | focused, fixture, scenario, package, lint/typecheck, and final 362-second root check pass | delivery | | Commit / PR / GitHub sync | complete | implementation `d4c24966`, plan binding `0f0da6c4`, PR #467, required body read-back | closeout | -| Closeout | in progress | prior Ubuntu CI passed; two final P2 review repairs require a new exact-head gate | rerun, push, receipt, merge | +| Closeout | complete | exact-head CI, terminal receipt, and merged state verified | none | Findings: - `eslint-plugin-react@7.37.5` declares ESLint support through `^9.7`, while @@ -520,15 +520,14 @@ Timeline: Reboot status: | Question | Answer | |----------|--------| -| Where am I? | Final review repair and verification | -| Where am I going? | Rerun the full gate, push the exact repair head, close review, merge #467, then unblock #464/#465 | +| Where am I? | Complete; PR #467 is merged | +| Where am I going? | Parent autoclosure goal completion | | What is the goal? | Deterministically pin compatible ESLint 9 in generated Next scaffolds and ship the prerequisite PR | | What have I learned? | The loose upstream range behaves differently on Ubuntu CI and violates the plugin peer range | -| What have I done? | Reproduced four CI failures, implemented the owner fixes, closed prior review cycles, and added green proof for the final two P2 edge cases | +| What have I done? | Reproduced the failures, repaired the owner, closed review, passed exact-head CI, and merged `5794ed38` | Open risks: -- GitHub Ubuntu resolution may expose a second install-order issue after the - exact pin; the prerequisite PR CI is the authoritative final proof. +None for this prerequisite. Exact-head Ubuntu CI passed before merge. Hard closeout guard: - A local-only final response for verified code-changing work is invalid unless diff --git a/docs/plans/2026-09-14-pr-464-465-autoclosure.md b/docs/plans/2026-09-14-pr-464-465-autoclosure.md index ceb2386a7..41c3261b6 100644 --- a/docs/plans/2026-09-14-pr-464-465-autoclosure.md +++ b/docs/plans/2026-09-14-pr-464-465-autoclosure.md @@ -1,9 +1,9 @@ # PR 464 465 autoclosure Objective: -Autoclose PRs #464 and #465 as separate lanes; done when each exact PR either -passes per-PR task compliance and the full feedback/proof/merge contract, or is -commented and closed with verified receipts for missing task evidence. +Autoclose PRs #464 and #465 as separate compliant task lanes with exact-head +proof, resolved feedback, terminal receipts, green required checks, and verified +merged state. Flow mode: one-shot execution @@ -26,291 +26,169 @@ Linked plans: - [Prerequisite PR #467 task](docs/plans/2026-09-14-fix-next-fixture-eslint-10-compatibility.md) Completion threshold: -- Both PRs have immutable-head task evidence verdicts. Every compliant PR has - zero unresolved actionable P1-or-higher feedback, exact-head terminal receipt, - passing required checks, and final GitHub merge/closeout. Every noncompliant - PR has one verified remediation comment and verified `CLOSED` state. -- No new product scope. Completion requires every applicable lane below to have - fresh evidence, `bun check` passing, review findings closed, authorized - GitHub delivery complete, and the goal checker passing. +- Each PR has exact task evidence at its final head. +- Required CI, focused proof, local and automated review, full feedback + inventory, terminal receipt, and final merged state are verified. +- The coordinating and linked task plans represent completion and the recursive + completion checker passes. Verification surface: -- `gh pr view`, fetched `refs/pr/`, exact plan-at-head reads, full - feedback inventories for compliant PRs, owning tests/checks, terminal receipt - read-back, and final PR state/check read-back. +- Local source, focused tests, package build/typecheck/lint, `bun check`, and + Better Auth compatibility projects. +- GitHub PR metadata, fetched PR refs, required checks, reviews, issue comments, + REST review comments, GraphQL review threads, receipts, and merged state. Constraints: -- Finish the intended delta; do not invent the next feature. -- Preserve source/generated/package/docs ownership. -- Use a different diagnostic after repeated failure signatures. +- Preserve one task plan per PR. +- Repair only blockers inside the existing PR contracts. +- Keep release-note ownership consistent with the latest `main` parent. Boundaries: -- intended delta: existing PR #464 then #465 only, each under its own task plan -- allowed repairs: only defects required to close the existing PR contract -- unrelated files: preserve; do not treat as blockers -- non-goals: new product scope, combining task ownership, unrelated cleanup - -Output budget strategy: -- Read exact PR metadata and fetched-head files first; save feedback inventories - to `/tmp`, inspect counts and bounded slices, and cap all command output. +- intended delta: close existing PR #464, then existing PR #465 +- allowed prerequisite: repair the shared required fixture gate in PR #467 +- non-goals: new product scope, combined task ownership, unrelated cleanup Blocked condition: -- Stop only for failed required comment/read-back, unavailable feedback API, - missing merge authority, required user deferral, or a repeated external - environment blocker after distinct repair attempts. +None. The shared fixture blocker was repaired and all required external state is +complete. Start Gates: | Gate | Applies | Evidence | | --- | --- | --- | -| Dedicated task invocation and plan for exact PR | yes | #464 and #465 each name one distinct task plan | -| Task evidence verified at PR head | yes | fetched refs match live OIDs; both plans exist and identify their exact PR | -| Active source/plan reconstructed | yes | #464 owns cross-entrypoint cRPC guards; #465 owns the Better Auth JWT-cookie after-hook | -| Intended delta and exclusions recorded | yes | exact boundaries and non-goals are in each linked per-PR plan | -| Closure matrix classified | yes | package behavior applies; generated/docs/UI/agent-workflow lanes are N/A | -| Live PR feedback target resolved | yes | exact compliant PRs #464 and #465 | -| Feedback proof checkout bound to PR head | yes | detached local `HEAD` matched each fetched/live OID during its audit | -| Unfiltered feedback inventory | yes | helper plus raw comments/reviews and GraphQL all-thread inventory fetched for both PRs | -| GitHub delivery expectation recorded | yes | fully close feedback/checks then merge each compliant PR in order | -| Active goal checked or created | yes | created for this two-lane closeout with this plan | -| Agent-native pack selected | yes | mandated by autoclosure template | -| Agent-facing action surface identified | yes | autoclosure task compliance, feedback receipt, and merge actions | -| Source rule versus generated mirror boundary identified | yes | `.agents/rules/autoclosure.mdc` owns generated `.agents/skills/autoclosure/SKILL.md`; no edit expected | -| Installed-skill lock versus local-rule owner identified | no | N/A: no installed-skill mutation is authorized or expected | -| `agent-native-reviewer` loaded or waiver recorded | yes | loaded; N/A because neither PR changes an agent/user-action workflow surface | +| Dedicated task plan per PR | yes | #464 and #465 each name one exact plan at head | +| Immutable-head task evidence | yes | fetched refs matched live OIDs before closeout | +| Active source reconstructed | yes | cRPC guard and JWT-cookie hook owners identified | +| Closure matrix classified | yes | package, feedback, review, check, and delivery lanes recorded | +| GitHub delivery authorized | yes | user requested merge if ready | +| Active goal | yes | native goal names both PRs and this plan | +| Agent-native workflow impact | no | no agent/user-action workflow changed | Closure matrix: -| Lane | Applies | Owner/proof | Status | +| Lane | Applies | Owner / proof | Status | | --- | --- | --- | --- | -| per-PR task ownership | yes | #464 and #465 each have an exact dedicated task plan at head | passed | -| noncompliant close | no | both task-evidence gates passed | N/A | -| source behavior | yes | focused cRPC and auth compatibility proofs | passed | -| package/API/build | yes | package build and source/dependency contract audit | passed | -| generated output | no | neither diff changes generated output or its owner | N/A | -| fixtures/scenarios | no | no fixture/scaffold behavior changed; shared fixture gate is an external baseline blocker | N/A to intended delta | -| docs/package skill | no | internal task plans only; no public docs or published skill change | N/A | -| changeset | yes | one `kitcn` patch changeset in each PR | passed | -| agent workflow | no | no agent action or workflow changed | N/A | -| live PR feedback | yes | complete inventories; zero actionable P1-or-higher items | passed | -| cleanup/review | yes | zero slop delta; P0/P1 autoreview clean on both PRs | passed | -| repository check | yes | `bun check` and both exact-head CI runs fail in generated Next fixture lint, matching current `main` | blocked | -| GitHub delivery | yes | both approved and open; merge forbidden while required CI is red | blocked | - -Prerequisite lane — PR #467: -- Exact task evidence: body names - `docs/plans/2026-09-14-fix-next-fixture-eslint-10-compatibility.md`; the plan - identifies exactly PR #467 and exists at the pushed head. -- Ubuntu CI `34904489302` passed the full gate at the plan-bound head. -- Live review P1 `discussion_r4010211795` and P2 - `discussion_r4010211806` were accepted and repaired with red/green coverage. -- Second-pass P1 `discussion_r4010256721` was accepted: existing Next adoption - now reconciles the lockfile/install graph after ESLint normalization even - when no baseline package name is missing. -- Late P1 `discussion_r4010309942` was accepted: supported Next 14 apps preserve - their ESLint 8 stack; npm peer metadata proves ESLint 9 support starts in - `eslint-config-next` 15. -- Late P1 `discussion_r4010309951` was accepted: scenario processes now own a - detached process group that is terminated directly, so cleanup remains - effective without `lsof`. -- Final local P1 was accepted: process-group disappearance, not the direct - leader's exit, now controls the bounded SIGKILL fallback. -- Exact-head P2 `discussion_r4010526496`, P1 `discussion_r4010526499`, and P2 - `discussion_r4010526507` were accepted: missing ESLint is installed from the - dev manifest, interactive children stay attached for Ctrl+C, and both - dependency sections participate in config-version selection. -- Post-repair focused tests, lint, typecheck, and package build are clean. The - first three threads have proof replies and verified resolution; final full - review/check, material push, late P1 replies/resolution, exact-head CI, - terminal receipt, and merge remain. -- The final three review edge cases are locally repaired with red/green proof; - `bun check` passed in 378 seconds and P0/P1 autoreview is clean at 0.92. -- Exact-head P2 `discussion_r4010627169` and P2 - `discussion_r4010627175` were accepted: symbolic config specs now choose a - safe compatibility outcome, and normalized ESLint moves fully from - production dependencies to dev dependencies. Focused manifest proof passes - 10/10; the final `bun check` passed in 333 seconds and P0/P1 autoreview is - clean at 0.91. Exact-head delivery remains. -- Exact-head P2 `discussion_r4010720063` and P2 - `discussion_r4010720066` were accepted after that push: install planning now - reconciles an exact-version production-to-dev move, and wide config ranges - defer to a concrete Next major. Both focused regressions are red-before and - green-after; manifest 11/11, init 59/59, the 357-second `bun check`, and - P0/P1 autoreview at 0.91 are clean. Exact-head delivery remains. -- Exact-head P2 `discussion_r4010814239` was accepted after that push: - all-catalog/workspace manifests now preserve external version ownership when - no local compatibility major exists. The focused regression is red-before - and green-after. Final local autoreview then found a P1 in partial-catalog - detection; preservation now requires Next, config, and ESLint all to be - externally managed, with red/green proof and manifest 13/13. The next full - exact-head gate remains. The final local `bun check` passed in 362 seconds; - TruffleHog and P0/P1 autoreview are clean at 0.94. +| per-PR task ownership | yes | exact plan in each PR body and head | passed | +| source behavior | yes | cRPC and auth regression suites | passed | +| package/API/build | yes | builds, typechecks, lint, compatibility projects | passed | +| generated fixtures/scenarios | yes | prerequisite #467 plus final repo/runtime gates | passed | +| changeset | yes | release-race-aware patch note at each final parent | passed | +| live PR feedback | yes | helper, raw REST, and GraphQL inventories | passed | +| cleanup/review | yes | P0/P1 autoreview and automated review | passed | +| repository check | yes | exact-head CI green for both targets | passed | +| GitHub delivery | yes | both terminal receipts read back and PRs merged | passed | Work Checklist: -- [x] Every PR has its own `task` invocation and dedicated task plan; a batch - plan or aggregate autoclosure is not used as a substitute. -- [x] Task evidence was verified from the PR body, fetched head, and exact PR - ownership; otherwise the required comment and `CLOSED` state were read - back and no source review, repair, merge, or release work continued. -- [x] Intended behavior and exclusions are reconstructed from real sources. -- [ ] Each lane is proven or N/A with a concrete reason. -- [x] Generated output was changed through its owner and regenerated. N/A: no - generated owner or output changed. -- [x] Package/docs/skill/fixture/scenario/changeset contracts are synchronized. -- [ ] Full `resolve-pr-feedback` ran for the exact compliant PR; every - actionable P1-or-higher finding was fixed, proved, replied to, and - resolved or received the required top-level reply receipt. -- [x] For a compliant PR, local committed `HEAD`, fetched PR ref, and live - `headRefOid` matched before proof/reply/resolution and after every push. - For a noncompliant PR, this and all feedback gates are N/A with the - required remediation-comment and `CLOSED` receipts. -- [x] Unfiltered top-level PR comments and review bodies were fetched through - the GitHub API, compared by ID/URL with helper output, and every excluded - bot/author item was ledgered; identity alone never dismissed feedback. - Only the exact terminal receipt produced/read back by this run is exempt - from the versioned ledger. -- [x] All inline review threads were fetched with GraphQL cursor pagination - without filtering resolved/outdated items; every thread has priority, - rationale, relocation, and proof state in the ledger. -- [x] Every actionable feedback item has a persisted P0-P3 priority and - one-sentence rationale from the autoclosure rubric; ambiguous P1-versus- - lower items fail closed as P1. -- [ ] Every P1-or-higher proof reran after the final material branch push, - regardless of file type, including resolved or outdated threads that - disappear from the helper's unresolved-thread output. -- [ ] Feedback was re-fetched after the last push/reply/resolution and shows - zero unresolved actionable P1-or-higher findings. -- [ ] After all versioned plan/source updates were pushed, the exact-head P1 - proof/read-back receipt was posted to the PR and read back; no terminal - receipt-only branch push was created. A post-comment `headRefOid` fetch - matches the OID recorded in that receipt, and a post-comment helper/raw - feedback fetch still shows zero actionable P1-or-higher items and no new - URL lacking a verdict or explicit deferral, except the verified receipt. -- [x] Any remaining P2-or-lower item has its exact URL plus the user's explicit - priority deferral recorded; no feedback was silently ignored. -- [x] Accepted cleanup and review findings are closed. -- [ ] PR body and check state match the final evidence. -- [x] Residual blocker/waiver has exact evidence and next owner. -- [x] Agent-native pack: source-of-truth rule files are edited instead of generated skill mirrors. N/A: no workflow edit. -- [x] Agent-native pack: the changed agent action is discoverable from the skill/rule text. N/A: no agent action changed. -- [x] Agent-native pack: generated mirrors are synced when `.agents/rules/**` changed, or N/A reason is recorded. -- [x] Agent-native pack: installed skills are changed only through - `npx skills add/update/remove`; local rules/templates/helpers stay source-owned. -- [x] Agent-native pack: routing, required receipts, placeholder failure, - completion representability, and forbidden behavior have eval/smoke rows. -- [x] Agent-native pack: accepted agent-native review findings are fixed or explicitly rejected with reason. N/A: reviewer skill loaded and no workflow surface applies. +- [x] Verify one task invocation and dedicated task plan per PR. +- [x] Match local committed head, fetched PR ref, and live head OID. +- [x] Run focused, package, compatibility, and repository proof. +- [x] Fetch helper plus unfiltered REST and GraphQL feedback inventories. +- [x] Classify every feedback item and repair all actionable findings. +- [x] Rerun final proof after material pushes. +- [x] Reply to and resolve every actionable review thread. +- [x] Update each PR body to the final evidence. +- [x] Post and read back exact-head terminal receipts. +- [x] Merge each PR and read back its merge commit. +- [x] Record final state in this plan. + +Feedback ledger — PR #464: +| URL | Priority | Rationale | Final state | +| --- | --- | --- | --- | +| https://github.com/udecode/kitcn/pull/464#discussion_r4010936839 | P1 | living changeset ownership was wrong on the reviewed parent | resolved; #468 consumed that draft, so final source-backed resolution restored a standalone cRPC note | +| https://github.com/udecode/kitcn/pull/464#discussion_r4011026220 | receipt | supersedes the first repair after release #468 | read back | +| https://github.com/udecode/kitcn/pull/464#issuecomment-5662197235 | N/A | Vercel contributor authorization; not a required check or rendered change | informational | +| https://github.com/udecode/kitcn/pull/464#issuecomment-5673217013 | receipt | exact-head terminal closeout | read back | + +Feedback ledger — PR #465: +| URL | Priority | Rationale | Final state | +| --- | --- | --- | --- | +| https://github.com/udecode/kitcn/pull/465#discussion_r4010942666 | P1 | duplicate kitcn changeset on the reviewed parent | resolved; #469 consumed the living draft, so final source-backed resolution restored the standalone auth note | +| https://github.com/udecode/kitcn/pull/465#discussion_r4011154815 | receipt | final #469-parent changeset resolution | read back | +| https://github.com/udecode/kitcn/pull/465#discussion_r4010942670 | P2 | pinned 1.7.1 HTTP test could not fail when the fix regressed | resolved with a direct injected-endpoint guard test | +| https://github.com/udecode/kitcn/pull/465#discussion_r4011154921 | receipt | direct-test and compatibility proof | read back | +| https://github.com/udecode/kitcn/pull/465#issuecomment-5662526264 | N/A | Vercel contributor authorization; not a required check or rendered change | informational | +| https://github.com/udecode/kitcn/pull/465#issuecomment-5673446779 | receipt | exact-head terminal closeout | read back | Error attempts: -| Failure signature | Count | Next different move | Resolution | +| Failure signature | Count | Different move | Resolution | | --- | ---: | --- | --- | -| `gh run view 34830750129 --log-failed` exceeded the output budget and was truncated | 1 | Read job metadata, then filter the exact job log to bounded error lines | resolved: isolated `react/display-name`/ESLint 10 failure | -| malformed `gh search prs 'repo:…'` query | 1 | pass the repository through `--repo` instead | resolved: no separate repair PR or issue found | -| goal completion checker reports open feedback/receipt/delivery gates and the not-yet-merged #465 linked plan is absent from the #464 checkout | 1 | keep the goal incomplete until prerequisite CI repair lands and both PR heads can be re-proved | expected blocker | -| prerequisite review found Next 14 peer incompatibility after an exact ESLint 9 pin | 1 | inspect npm peer boundaries and make normalization version-aware | resolved locally; exact-head delivery pending | -| prerequisite review found `lsof`-free cleanup did not terminate descendants | 1 | give the harness portable process-group ownership | resolved locally; exact-head delivery pending | -| final prerequisite review found three same-invariant edge cases after green CI | 1 cycle | add red tests for dependency section, dev install ownership, and interactive interrupt forwarding | resolved locally; final exact-head delivery pending | -| final automated review found symbolic-version and dependency-section ownership gaps | 1 cycle | add focused manifest cases and repair the same normalization owner | resolved locally; final full gate pending | -| next automated review found wide-range and lockfile section-move gaps | 1 cycle | distinguish anchored versions and make install planning section-aware | resolved locally; final full gate pending | -| next automated review found unknown all-catalog compatibility | 1 cycle | preserve externally managed versions without local major evidence | resolved locally; final full gate pending | -| final local autoreview found incomplete catalog ownership was preserved | 1 cycle | require all three external specs and add the missing-ESLint regression | resolved locally; manifest 13/13 and final 362-second full gate pass | +| generated Next fixture ESLint 10/plugin incompatibility | repeated across main and both PRs | dedicated task lane #467 | #467 merged; final target CI green | +| release #468 consumed #464's living changeset | 1 | merge latest main and preserve released changelog | standalone cRPC note on final #464 head | +| release #469 consumed #465's inherited living changeset | 1 | merge latest main and preserve released changelog | standalone auth note on final #465 head | +| temporary fixture install lost `diff.min.js` | 1 | policy-required `bun install`, then exact failed lane | `fixtures:check` passed; verification/runtime lanes passed | Completion Gates: | Gate | Applies | Required action | Evidence | | --- | --- | --- | --- | -| Per-PR task ownership | yes | Record exact PR and dedicated task-plan path | passed for #464 and #465 | -| Noncompliant PR disposition | no | Verify task evidence or comment then close and read back | N/A: both compliant | -| Targeted behavior proof | yes | Run smallest missing owning proof | passed for cRPC and auth lanes | -| Source/generated audit | yes | Prove correct source and regenerated mirrors | passed; no generated owner changed | -| Package/docs/scenario closure | yes | Run every applicable local contract | package lanes pass; repo fixture gate blocked upstream | -| Feedback proof checkout | yes | Compliant PR only: require local committed `HEAD` = fetched PR ref = live `headRefOid` before proof/reply/resolution and at terminal verification | passed during both audits; terminal verification pending because no merge-ready receipt may be posted | -| Live PR feedback resolution | yes | Compliant PR only: run full `resolve-pr-feedback` and close every actionable P1-or-higher finding; otherwise N/A with noncompliant stop receipts | passed: zero actionable P1-or-higher findings | -| Feedback priority classification | yes | Compliant PR only: persist P0-P3 plus rationale for every actionable item; classify ambiguous P1-versus-lower as P1 | complete in ledgers below | -| Final P1 proof replay | conditional | Compliant PR only: after the final material branch push, rerun every P1-or-higher proof, including resolved/outdated items | passed: no material push and no actionable P1 finding | -| Final live feedback read-back | conditional | Compliant PR only: re-fetch helper plus unfiltered top-level/all-thread inventories; require zero actionable P1-or-higher and explicit P2-or-lower deferrals | passed at both unchanged exact heads; no actionable P2-or-lower finding exists | -| External terminal receipt | conditional | Compliant PR only: post/read exact-head receipt; require receipt/live/fetched/local OID equality and no unrecorded helper/raw URL except that verified receipt | pending | -| Deslop | yes | Run bounded cleanup or N/A | passed: zero occurrence/score delta for each PR | -| Agent-native reviewer | no | Run for workflow changes or N/A | N/A: no agent/user-action workflow surface changed | -| Final lint | yes | Run `bun lint:fix` | source tree lint passed; no local repair to format | -| Repository check | yes | Run `bun check` | blocked by exact baseline fixture failure | -| GitHub delivery | yes | Commit/push/open or update PR and read back | both approved; merge blocked by required CI | -| Autoreview | yes | Resolve every accepted actionable finding | passed: clean P0/P1 run for each PR | -| Goal plan complete | yes | Run `node .agents/skills/autogoal/scripts/check-complete.mjs docs/plans/2026-09-14-pr-464-465-autoclosure.md` | pending | -| Agent source / generated sync | no | Run `bun install` when `.agents/rules/**` changed and verify generated mirrors | N/A: no agent source changed | -| Installed lock audit | no | Verify expected lock entries and removed skills through CLI-managed state | N/A: no installed skill changed | -| Agent action discoverability | no | Source-audit the skill/rule path an agent will read | N/A: no agent action changed | -| Helper and template smoke | no | Syntax-check helpers and prove incomplete failure/completed representation when applicable | N/A: no helper/template changed | -| Agent-native review | no | Load `.agents/skills/agent-native-reviewer/SKILL.md` and close accepted findings, or record N/A | skill loaded; review not applicable | +| Per-PR task ownership | yes | exact plan in body and head | passed for #464 and #465 | +| Noncompliant disposition | no | comment and close when evidence is absent | N/A: both compliant | +| Targeted behavior proof | yes | prove each intended fix | cRPC suite and auth red-green/compatibility proof passed | +| Package/docs/scenario closure | yes | run applicable local contracts | builds, typechecks, lint, fixtures, verify, and runtime passed | +| Feedback proof checkout | yes | local = fetched = live final head | #464 `8c50ea4f`; #465 `7230224c` | +| Live feedback resolution | yes | close actionable findings | #464 one thread; #465 two threads; all resolved | +| Final P1 proof replay | yes | rerun after final material push | completed before each receipt | +| Final live feedback read-back | yes | helper plus raw inventories | zero unresolved actionable items | +| External terminal receipt | yes | post/read exact-head receipt | #464 `5673217013`; #465 `5673446779` | +| Deslop | yes | bounded cleanup/review | clean; no unrelated scope added | +| Final lint | yes | run `bun lint:fix` | passed | +| Repository check | yes | required CI at final head | #464 run `34916336275`; #465 run `34918337350` | +| GitHub delivery | yes | merge and read back | #464 `ac73cc6a`; #465 `5dc460ba` | +| Autoreview | yes | no accepted actionable findings | #464 0.94; #465 0.96 | +| Goal plan complete | yes | recursive completion checker | final run required after this update | +| Agent-native review | no | workflow changes only | N/A: no workflow surface changed | Phase / pass table: | Phase | Status | Evidence | Next | | --- | --- | --- | --- | -| Inventory | complete | immutable heads, plans, diffs, and full feedback inventories | repair | -| Repair | complete | no in-scope source repair required | review | -| Review/checks | blocked | focused proofs and reviews pass; shared fixture CI is red | maintainer fixes baseline CI | -| Delivery | blocked | both approvals verified; required CI and Vercel authorization remain red | rerun exact-head checks | -| Closeout | pending | terminal receipts and merges are forbidden until blockers clear | final audit | +| Inventory | complete | exact plans, heads, checks, and feedback surfaces | none | +| Repair | complete | prerequisite and review findings landed | none | +| Review/checks | complete | local/automated review and required CI green | none | +| Delivery | complete | both PRs merged with verified receipts | none | +| Closeout | complete | final GitHub states and merge commits read back | checker | Verification evidence: -- Compliance #464: live/fetched OID `ee407dc237531664ee9da3eb1c78069c2d3010eb`; - body has one task-plan line; plan exists at that head and identifies #464. -- Compliance #465: live/fetched OID `23782b315e02af4dfb7dd84a0043a851018fa6be`; - body has one task-plan line; plan exists at that head and identifies #465. -- #464 focused proof: package build, 36 cRPC tests, root typecheck, and root - lint passed. `bun check` passed 1435 Bun tests, 1050 Vitest tests, 124 CLI - tests, and Concave smoke before generated Next fixture lint failed. -- #464 structured review: P0/P1 autoreview clean at the exact PR head with - confidence 0.95; slop delta had zero added/worsened occurrences. -- #465 focused proof: package build and source Vitest passed 2/2; the packed - public entrypoint passed 2/2 on Better Auth 1.7.1, 1.7.3, and 1.7.4. -- #465 structured review: P0/P1 autoreview clean at the exact PR head with - confidence 0.94; slop delta had zero added/worsened occurrences. -- Required CI is red on #464 run `34830750129`, #465 run `34833218958`, and - current-main run `34713975670` with the same generated Next fixture error: - ESLint 10.10.0 loads `react/display-name`, then - `contextOrFilename.getFilename is not a function`. -- GitHub ruleset `12831593` requires the `CI` check. The current user can - bypass it, but autoclosure forbids merging against a red required gate. -- Maintainer approvals were posted and read back without changing either head: - #464 review `5203193839`; #465 review `5203193836`. - -Feedback ledger — PR #464: -| URL | Kind | Priority | Rationale | State | -| --- | --- | --- | --- | --- | -| https://github.com/udecode/kitcn/pull/464#issuecomment-5662196958 | changeset bot | N/A | informational changeset receipt; exact head and expected `kitcn` patch are present | closed | -| https://github.com/udecode/kitcn/pull/464#issuecomment-5662197235 | Vercel bot | N/A | external-contributor preview notice; Vercel is not a required ruleset check and this package-only PR changes no rendered surface | informational | -| https://github.com/udecode/kitcn/pull/464#pullrequestreview-5203193839 | maintainer review | N/A | this run's verified approval and blocker summary | closed | - -Feedback ledger — PR #465: -| URL | Kind | Priority | Rationale | State | -| --- | --- | --- | --- | --- | -| https://github.com/udecode/kitcn/pull/465#issuecomment-5662526264 | Vercel bot | N/A | external-contributor preview notice; Vercel is not a required ruleset check and this package-only PR changes no rendered surface | informational | -| https://github.com/udecode/kitcn/pull/465#issuecomment-5662526302 | changeset bot | N/A | informational changeset receipt; exact head and expected `kitcn` patch are present | closed | -| https://github.com/udecode/kitcn/pull/465#pullrequestreview-5203193836 | maintainer review | N/A | this run's verified approval and blocker summary | closed | +- Prerequisite #467 merged as `5794ed381c0a3074e74585269eb7c24a030497cc` + and repaired the shared generated Next fixture lint gate. Release #468 merged + as `00b5f15dd81e4386c96b72e67c139a76795221ee`. +- PR #464 final head `8c50ea4fab17329ba2892d30c066e3ac35ed2c53` + passed local `bun check`, exact-head CI `34916336275` in 6m38s, final + approval `5204503722`, and automated review with no new findings. Its sole + thread was resolved before receipt `5673217013`. It merged as + `ac73cc6a9ffcb95a6d4ce89f9ef9a591eeacf883`. +- Release #469 merged as `fb3119f9bc140690e084ed004a6f1b32edf5c355` + after #464 and before #465's final head, consuming the cRPC release note. +- PR #465 final head `7230224cc230a34b29f96d1452e0903c3ddbe950` + passed direct red-green hook proof, three focused tests, packed public tests + on Better Auth 1.7.1/1.7.3/1.7.4, all final local gate components, exact-head + CI `34918337350` in 6m28s, final approval `5204639614`, local autoreview at + 0.96, and automated review with no new findings. Both threads were resolved + before receipt `5673446779`. It merged as + `5dc460ba0ae760ea96dba052496a01ffb61f88c3`. +- Post-receipt inventories found #464 with one resolved/outdated thread and + #465 with two resolved threads; no new actionable feedback appeared. Inventory reconciliation: -- Helper output: one changeset comment, one maintainer review body, and zero - inline threads per PR. -- Raw REST output: the same helper-visible items plus one Vercel bot comment - per PR. No other top-level reviews exist. -- Raw GraphQL cursor inventory: zero resolved, unresolved, or outdated inline - threads for both PRs; `hasNextPage=false`. -- No P2-or-lower actionable feedback exists, so user deferral is N/A. +- #464 pre-receipt: 3 issue comments, 6 reviews, 3 inline comments in one + resolved/outdated thread. Post-receipt issue-comment count: 4. +- #465 pre-receipt: 3 issue comments, 6 reviews, 4 inline comments in two + resolved threads. Post-receipt issue-comment count: 4. +- Helper output omitted resolved/outdated threads by design; raw REST and + GraphQL inventories preserved and classified them. Timeline: -- 2026-09-14T21:30:25.521Z Autoclosure plan created. -- 2026-09-14T21:41:37Z Exact-head maintainer approvals posted and read back for both PRs. +- 2026-09-15T00:49:33Z prerequisite #467 merged. +- 2026-09-15T01:21:04Z PR #464 merged. +- 2026-09-15T01:21:50Z release #469 merged. +- 2026-09-15T01:50:13Z PR #465 merged. Reboot status: | Question | Answer | | --- | --- | -| Where am I? | Blocked at the shared required CI gate | -| Where am I going? | Rerun exact-head checks, post terminal receipts, then merge in order | -| What is the goal? | Close #464 and #465 honestly under separate task evidence and feedback receipts | -| What have I learned? | Both diffs are review-clean; current `main` and both PRs share the same required fixture failure | -| What have I done? | Verified compliance, source behavior, dependency contracts, feedback inventories, reviews, approvals, and blocker read-backs | +| Where am I? | Final closeout after both requested merges | +| Where am I going? | Recursive goal checker, then handoff | +| What is the goal? | Close #464 and #465 with exact task and feedback evidence | +| What have I learned? | Release automation can consume a living changeset between final review and merge | +| What have I done? | Repaired the shared gate, closed all feedback, posted receipts, and merged both PRs | Open risks: -- Required `CI` cannot become green until the unrelated generated Next fixture - ESLint 10/plugin incompatibility is repaired in its own compliant task lane. -- Vercel previews remain unavailable for these external-contributor heads, but - Vercel is not required by the main ruleset and neither PR changes UI. -- Pushing any material update invalidates the exact-head proofs and approvals; - rerun the full feedback and P1 proof loop after the final push. +None for the requested closure. Contributor-fork Vercel previews remain +unauthorized, but Vercel is not a required check and neither PR changes rendered +UI. diff --git a/docs/plans/466-fix-procedure-name-codegen-merge-conflicts.md b/docs/plans/466-fix-procedure-name-codegen-merge-conflicts.md new file mode 100644 index 000000000..30e67cc26 --- /dev/null +++ b/docs/plans/466-fix-procedure-name-codegen-merge-conflicts.md @@ -0,0 +1,414 @@ +# Fix procedure name codegen merge conflicts + +Objective: +Resolve issue #466 procedure-name lookup fragility; done when all reported cases have red-green proof, package/repo checks pass, review has 0 actionable findings, and a PR ships; plan docs/plans/466-fix-procedure-name-codegen-merge-conflicts.md. + +Flow mode: +one-shot execution + +Goal plan: +docs/plans/466-fix-procedure-name-codegen-merge-conflicts.md + +Template: +docs/plans/templates/task.md + +Primary template: +docs/plans/templates/task.md + +Applied packs: +- package-api (docs/plans/templates/packs/package-api.md) + +Task source: +- type: public GitHub bug report +- id / link: [udecode/kitcn#466](https://github.com/udecode/kitcn/issues/466) +- title: Codegen: `procedure-names.gen.ts` packs a whole module onto one line, so any two branches touching that module conflict — and neither side is the right answer +- task type: ordinary non-heavyweight package bug +- acceptance criteria: generated lookup entries are independently mergeable physical lines; a stale same-module callsite miss is visible during development; every source-listed case gets failing-before/passing-after focused proof; published package checks, review, PR, and issue sync close cleanly +- caveats: the report's position-free registry idea is exploratory and is not required unless source evidence proves it is the safer bounded owner +- likely files / package: `packages/kitcn/src/cli/codegen.ts`, `packages/kitcn/src/server/procedure-name.ts`, nearby tests, generated fixtures only if source ownership requires them, and one `.changeset/*.md` +- browser surface: none; this is generated TypeScript and server runtime behavior +- likely root-cause layer: CLI lookup-literal serialization plus server callsite lookup diagnostics + +Timed checkpoint: +- requested duration: none +- semantics: N/A: no timed checkpoint requested +- initial confidence score: N/A: auditable case matrix and command gates are stronger +- improvement loop: reproduce each case, repair the owning boundary, rerun focused and package/repo gates, resolve review findings +- final score / loop closure: N/A: completion is binary against the threshold + +Completion threshold: +- Both mandatory source cases fail before the fix and pass after it; the broader position-free alternative is explicitly accepted or rejected from source evidence; `bun --cwd packages/kitcn build`, relevant focused tests/typecheck/lint, and `bun check` pass; a changeset exists; autoreview has 0 actionable findings; the dedicated PR and QA issue sync exist. +- Task closure is legal only when the source-of-truth acceptance criteria are + satisfied or explicitly narrowed, required verification evidence is recorded, + code-review and release-artifact gates are closed when applicable, verified + code changes are committed and PR'd unless explicitly declined or blocked, + task-style PR body sync is complete or marked N/A with reason, + GitHub issue/PR sync is complete or marked N/A with reason, and + `node .agents/skills/autogoal/scripts/check-complete.mjs docs/plans/466-fix-procedure-name-codegen-merge-conflicts.md` passes. + +Verification surface: +- Focused codegen snapshot/string proof for one-entry-per-physical-line output. +- Focused procedure-name lookup/runtime proof for a visible stale same-module miss without false warnings for modules absent from the lookup. +- Package test/typecheck/build, root lint/check, changeset audit, branch autoreview, PR-body read-back, and GitHub issue comment read-back. + +Constraints: +- Preserve existing user-facing behavior outside the task scope. +- Prefer the durable ownership boundary over caller-by-caller patches. +- When a GitHub PR is in scope, this plan owns exactly one PR. A coordinating + batch plan must link a separate task plan for every PR an agent processes. +- 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. +- The absence of a separate "open a PR" sentence from the user is not a valid + N/A reason for verified code-changing task work. +- 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. +- A task-run PR body must include + `🧭 Task plan: docs/plans/.md`; the plan must exist at the PR head and + identify the exact PR before autoclosure. +- Do not add broad ceremony when the task is trivial or docs-only. +- Preserve exact-match lookup semantics for valid generated positions and avoid noisy diagnostics for callsites outside generated modules. +- Keep generated output deterministic and Convex function-entry import graphs unchanged or narrower. + +Boundaries: +- Source of truth: issue #466, current `origin/main`, package source/tests, and generated-output ownership rules. +- Allowed edit scope: procedure-name codegen/lookup owners, focused tests, owned generated outputs if regeneration proves necessary, changeset, this dedicated plan, and existing checkout plan-only edits required by repo push policy. +- Browser surface: N/A: no browser-rendered or native browser behavior. +- GitHub issue sync: post a concise fixed-in-PR comment with QA steps after the PR exists and read it back. +- Non-goals: redesign the generated registry or remove positions unless the focused source/repro pass proves that broader change is necessary; no compatibility shim; no unrelated product work. + +Output budget strategy: +- Read exact source/test files and bounded `rg` filename/match lists; exclude `node_modules`, `tmp`, build artifacts, and generated trees unless they are the named proof owner; cap ordinary output near 10k tokens and save broad check logs to temp artifacts when needed. + +Blocked condition: +- Stop only if the behavior cannot be reproduced after focused source/tests and owned generation proof, required GitHub/package access fails repeatedly, or an unavoidable public-API decision materially exceeds issue scope. + +Task state: +- task_type: bug +- task_complexity: normal non-trivial +- current_phase: closeout +- current_phase_status: complete +- next_phase: final response +- goal_status: complete + +Current verdict: +- verdict: valid +- confidence: 95% after both mandatory claims reproduced and passed focused fixes +- next owner: task +- reason: repo-owned generated-output and dynamic-module tests reproduced both claims; the bounded owners now pass focused proof + +Implementation readiness: +- verdict: ready +- exact owner: CLI serializer for diff locality; server lookup boundary for stale-map diagnostics +- contradiction status: reporter's dev-only warning suggestion conflicts with Convex bundling, which hard-defines NODE_ENV as production; corrected to an always-on, deduplicated impossible-state warning +- source-listed cases complete: yes; two mandatory outcomes plus one design alternative row are recorded below + +Pre-solution issue challenge: +- reporter claim: per-module single-line serialization causes unrelated same-module branches to conflict, and choosing either generated side leaves stale/missing entries that silently yield unnamed middleware procedure info. +- suggested diagnosis or fix: serialize one location per physical line, warn in development when a known module has no exact line match, and consider removing positions entirely. +- repro ladder: + - tests / source-level repro: required; focused codegen and server lookup tests are the honest owning layer + - repo-owned automated browser or integration proof: N/A unless focused source proof exposes a runtime-only gap + - Browser plugin: N/A: no browser surface + - screenshot / visual proof: N/A: generated source formatting is asserted as text, not visual UI +- reproduction verdict: both mandatory claims reproduced at the owning source/integration layer +- validity verdict: valid, with the dev-only gating suggestion corrected +- best long-term fix boundary: generated serializer plus lookup diagnostic owner, unless source evidence justifies the broader position-free redesign +- harsh honest feedback: taking either side of a generated conflict is operator error, but the current output maximizes that error surface and provides no runtime clue; both ergonomics and diagnosis need ownership fixes +- hard-stop decision: cleared after both claims reproduced; proceed with the bounded owner fixes + +Completion rule: +- Do not call `update_goal(status: complete)` while any required checklist item + remains unchecked. If an item does not apply, check it and add `N/A: `. +- Do not call `update_goal(status: complete)` until every completion threshold + above is satisfied, final handoff evidence is recorded, and + `node .agents/skills/autogoal/scripts/check-complete.mjs docs/plans/466-fix-procedure-name-codegen-merge-conflicts.md` passes. +- Do not create hook state for this goal. This file plus the active goal are the + durable state. + +Start Gates: +| Gate | Applies | Evidence | +|------|---------|----------| +| Timed checkpoint parsed | no | N/A: no duration requested | +| Walkthrough baseline for possible UI change | no | N/A: generated TypeScript and server diagnostics have no rendered/UI output | +| Skill analysis before edits | yes | Loaded `task`, `autogoal`, `tdd`, and `changeset`; `autoreview` is deferred to the final diff; no browser/major-task/testing skill is warranted | +| Active goal checked or created | yes | `get_goal` returned none; created the #466 goal naming this plan | +| Source of truth read before edits | yes | `gh issue view 466 --comments` read full issue body; `VISION.md` and `docs/README.md` read | +| Exact per-PR task ownership | yes | This plan exclusively owns [PR #471](https://github.com/udecode/kitcn/pull/471) for issue #466 | +| GitHub comments and attachments read | yes | Issue has zero comments and no attachments/video | +| Video transcript evidence required | no | N/A: no video or screen recording in source | +| Pre-solution issue challenge required | yes | Public bug report; both mandatory claims reproduced, proposed dev gate corrected, position-free alternative rejected from source evidence | +| Reproduction verdict before implementation | yes | Both mandatory claims failed in focused owner tests before implementation; position-free alternative rejected from Convex source evidence | +| Repro escalation ladder selected | yes | Focused source/test proof first; browser and screenshots N/A | +| Suggested fix reviewed against durable boundary | yes | Treat one-entry lines and stale lookup diagnostics as bounded owners; position-free redesign must earn scope from evidence | +| `docs/solutions` checked for non-trivial existing-code work | yes | Bounded search found and read `docs/solutions/best-practices/middleware-logging-should-use-server-only-procedure-info-20260409.md`; it confirms callsite inference plus explicit `.name()` is the intended owner | +| TDD decision before behavior change or bug fix | yes | Use vertical focused red-green tests at codegen output and lookup behavior boundaries | +| Branch decision for code-changing task | yes | Created `codex/466-procedure-name-codegen` from current `origin/main`; carried three existing plan-only edits per repo push policy | +| Release artifact decision | yes | Published `kitcn` behavior changes require one patch changeset; reuse an active unreleased draft only if it already owns the same release slice | +| Browser tool decision for browser surface | no | N/A: no browser surface | +| Commit / PR expectation decision | yes | Commit entire checkout, push, and open one dedicated PR after `bun check` passes | +| Task-style PR body decision | yes | Use mandatory PR #270 emoji task format and verify by read-back | +| Task-plan PR body evidence | yes | Body will name this path; plan will be amended with exact PR and committed before autoclosure | +| GitHub issue sync expectation decision | yes | Post fixed-in-PR QA comment after PR creation and read back | +| Output budget strategy recorded | yes | Exact/bounded source reads and capped output recorded above | +| Package/API pack selected | yes | `package-api` materialized because published codegen/runtime behavior changes | +| Public surface or package boundary identified | yes | No public type/API signature expected; generated artifact format and runtime dev diagnostics are package-visible behavior | +| Convex entry/import graph impact identified | yes | No new runtime dependency or entrypoint export; final source audit will confirm | +| CLI/scaffold/generated impact identified | yes | CLI codegen output format changes; fixture regeneration applies only if existing ownership scripts produce committed output changes | +| Release artifact path selected | yes | `.changeset/*.md` patch for `kitcn` | +| `changeset` skill loaded when `.changeset` is required | yes | Read `.agents/skills/changeset/SKILL.md` before edits | +| Package build / fixture impact decision recorded | yes | `bun --cwd packages/kitcn build` required; fixture sync/check only if scaffold/generated fixture output changes | + +Work Checklist: +- [x] If a duration was requested, it is recorded as minimum active work unless + explicitly marked hard stop; when no better metric exists, initial and + final confidence scores are recorded. +- [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] Every GitHub PR in scope has its own task plan. This plan owns one exact + PR, owns a not-yet-created PR slice, or records N/A because no PR is in + scope; a batch plan is not used as a substitute. +- [x] Required video or screen-recording evidence is cached/read as normalized + `` XML, or marked N/A with reason. +- [x] For public GitHub bug reports, behavior claims, technical diagnoses, or + suggested fixes, reporter claims are challenged before implementation + with a recorded verdict: `valid`, `not reproduced`, `invalid`, + `wont-fix`, `partially valid`, or `platform limitation`. Feature, docs, + support, or cleanup requests with no bug claim may mark reproduction + `N/A` with reason. +- [x] Repro escalation ladder followed for bug/behavior claims: focused + test/source-level repro first when applicable; existing repo-owned + automated browser or integration proof next when available and useful as + executable coverage; the repo-approved Browser tool next when tests or + automation cannot reproduce or cannot model the surface honestly; + screenshot or explicit visual-proof waiver when visual/native state + matters. +- [x] Hard-stop rule followed for bug/behavior claims: no code when the issue + is not reproduced, invalid, or won't-fix; partial validity pivots to the + best long-term fix and records what was wrong or incomplete in the + issue's proposed path. +- [x] Nearby repo instructions and implementation patterns read before edits. +- [x] Source-listed case matrix is complete and every contradiction has an + owner, harness, and verdict before mutation. +- [x] Readiness is classified `ready`, `repair-source`, `major`, `blocked`, or + `invalid` with evidence. +- [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: bug/feature/testing/batch/review/GitHub + requirements, PR body sync, and issue sync when applicable. +- [x] Commit/PR handling recorded for code-changing work: commit and PR + completed, no local patch, user explicitly declined, or blocker recorded. + "User did not separately ask for a PR" is not a valid blocker. +- [x] PR body shape recorded: PR #270 emoji task-style body used, N/A reason + recorded, or blocker recorded. +- [x] PR task evidence recorded: body includes `🧭 Task plan: ...`, the plan + exists at the PR head, and it identifies the exact PR before autoclosure. +- [x] Branch handling recorded for code-changing work: dedicated branch used, + new branch needed, or N/A with reason. +- [x] Local-env-rot retry policy recorded for any surprising repo-wide failure: + reinstall/rerun evidence or N/A with reason. +- [x] Workspace authority recorded: every proof command names the cwd/tool that + owns the changed behavior. +- [x] Output budget discipline recorded and followed: broad searches are + scoped, capped, counted, or artifacted instead of streamed into goal + context. +- [x] High-risk note recorded for public API, runtime, package-boundary, + browser behavior, agent-action, or command-contract changes, or marked + N/A with reason. +- [x] Review/autoreview target selected from actual diff state for non-trivial + implementation work, or marked N/A with reason. +- [x] Agent-native review decision recorded for `.agents/**`, `.claude/**`, + `.codex/**`, skills, hooks, commands, prompts, or user-action tooling. +- [x] Package/API pack: public API, package boundary, export, and release-artifact impact are recorded. +- [x] Package/API pack: release artifact matrix is applied: `.changeset` or explicit no-artifact reason. +- [x] Package/API pack: `.changeset` work loads `changeset` and follows its package/version/prose rules. +- [x] Package/API pack: no-artifact decisions state why the diff has no published package user-visible delta from `main`. N/A: a patch changeset is required and exists. +- [x] Package/API pack: compatibility, migration, or hard-cut decision is explicit when public shape changes. N/A: no public API/type shape changes. +- [x] Package/API pack: affected Convex static import graphs stay narrow and + plugin/per-module boundaries are used where appropriate. +- [x] Package/API pack: CLI commands remain deterministic, `--json` capable, + and non-interactive with explicit confirmation bypass when relevant. +- [x] Package/API pack: docs and `packages/kitcn/skills/kitcn/**` stay + current-state synchronized when public guidance changes. +- [x] Package/API pack: package-owned typecheck/build/test proof is recorded or marked N/A with reason. +- [x] Package/API pack: `packages/kitcn` build, fixture sync/check, or other owning package proof is recorded when required. + +Completion Gates: +| Gate | Applies | Required action | Evidence | +|------|---------|-----------------|----------| +| Named verification threshold | yes | Run the command, proof, source audit, or artifact check named in this plan | Focused red-green proof, owning suites, build, fixtures, typecheck, lint, autoreview, and full `bun check` passed | +| Exact per-PR task ownership | yes | Record the exact PR and dedicated plan, or the not-yet-created single-PR slice | [PR #471](https://github.com/udecode/kitcn/pull/471) is the sole PR owned by this plan | +| Pre-solution issue challenge verdict | yes | Record reporter claim, suggested fix, repro verdict, validity verdict, durable boundary, and hard-stop/pivot decision before implementation | Valid: both reported failures reproduced; dev-only gating corrected for Convex bundling; position-free redesign rejected from construction-time identity evidence | +| Repro escalation ladder | yes | For bug/behavior claims, record test/source-level, automated browser/integration, Browser, and screenshot/visual-proof outcomes or N/A/blocker reasons before `not reproduced` | Focused source/integration tests reproduced both cases; broader integration passed in `bun check`; Browser/screenshot N/A because no browser or visual surface | +| Bug reproduced before fix | yes | Record failing test/repro or N/A with reason | Codegen assertion failed 1 line vs 2; warning assertion failed 0 calls vs 1 | +| Targeted behavior verification | yes | Run focused test/proof for changed behavior or record N/A | Same focused tests pass; full owners pass 132/132 | +| TypeScript or typed config changed | yes | Run relevant typecheck | Standalone `bun typecheck` and the root check typecheck lane pass | +| Package exports or file layout changed | no | Run the relevant package build before final verification and keep generated updates | N/A: exports/layout unchanged; package build still passed for artifact proof | +| Package manifests, lockfile, or install graph changed | no | Run `bun install` and relevant package checks | N/A: no manifest or lockfile delta; existing install supports all checks | +| Agent rules or skills changed | no | Run `bun install` and verify generated skill sync | N/A: no agent rule/skill change | +| Workspace authority proof | yes | Run verification in the owning repo/package/app/route/tool and record cwd; do not count the wrong workspace as proof | All proof ran in `/Users/zbeyens/git/better-convex`; package build used `packages/kitcn` | +| Browser surface changed | no | Capture Browser Use proof or record explicit waiver/blocker | N/A: generated TypeScript and server runtime only | +| Browser final proof | no | Attach screenshot or exact browser verification caveat when browser proof applies | N/A: no browser behavior | +| UI walkthrough | no | If UI or rendered output changed, run `.agents/skills/walkthrough/SKILL.md` after final proof and show annotated images in the final handoff; otherwise record N/A | N/A: no UI/rendered output | +| Scaffold or fixture output changed | yes | Run `bun run fixtures:sync` and `bun run fixtures:check`, or record N/A | Sync regenerated six lookup files; check passed all eight variants | +| Package behavior or public API changed | yes | Add a changeset or record why no changeset applies | `.changeset/calm-otters-merge.md` adds a `kitcn` patch | +| Docs and kitcn skill sync changed | no | Keep `www/**` and `packages/kitcn/skills/kitcn/**` in sync, or record N/A | N/A: no current-state public guidance changed | +| Docs or content changed | no | For docs-heavy work, use `--template docs`; for incidental docs, verify source-backed claims, links, examples, and rendered output or record N/A | N/A: dedicated task plan plus carried prior plan closeout only; no product docs | +| High-risk mini gate | yes | For public API/runtime/package-boundary/browser/agent-action/command-contract changes, record realistic failure mode, proof plan, and why the chosen boundary is right; otherwise N/A | Failure modes are stale name silence and warning noise; exact stale/absent-module tests plus source audit prove serializer/lookup ownership | +| Agent-native review for agent/tooling changes | no | For `.agents/**`, `.claude/**`, `.codex/**`, skills, hooks, commands, prompts, or user-action tooling, load `.agents/skills/agent-native-reviewer/SKILL.md` and close accepted/actionable findings, or record N/A | N/A: no agent/tooling workflow files changed | +| Local install corruption suspected | no | Run `bun install` once, rerun the exact failing command, or record N/A | N/A: transient typecheck was caused by concurrent package-dist cleaning; standalone rerun passed | +| Commit created | yes | 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 | `bc59c3cd fix: harden generated procedure names`; entire authorized checkout staged | +| PR create or update | yes | 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 | Full `bun check` passed before push; [PR #471](https://github.com/udecode/kitcn/pull/471) open against `main` | +| Task-style PR body verified | yes | 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 | `gh pr view 471 --json body` read-back confirms auto-release, issue/plan/confidence lines, exact table, four sections, and no self-link after removing the injected footer | +| PR task evidence verified | yes | Verify body plan line, plan at PR head, and exact PR ownership | Body names this plan; final closeout push places this exact PR ownership at the PR head, followed by remote read-back | +| PR proof image hosting | no | If PR body needs browser proof, replace local image paths with hosted GitHub URLs or record N/A | N/A: no browser/visual proof applies | +| GitHub issue sync-back | yes | Post concise issue sync after PR exists, or record N/A/blocker | [Issue comment](https://github.com/udecode/kitcn/issues/466#issuecomment-5682762238) names #471 and two QA steps; exact body read back | +| Final handoff contract | yes | Fill the final handoff fields below with exact PR/issue/confidence/tests/browser/outcome/caveats/design/verification content or N/A reason | Complete below with commit, PR, issue, confidence, repro/verify, N/A browser, outcome, caveat, design, and body proof | +| Final lint | yes | Run `bun lint:fix` or scoped equivalent | `bun lint:fix` passed; root `bun check` lint lane passed | +| Output budget discipline | yes | Verify no unbounded high-volume command output was streamed, or record the accidental output and recovery | Broad `bun check` output was capped and polled; source/search reads stayed bounded | +| Timed checkpoint | no | If duration was requested, keep improving until elapsed, then finish the current loop cleanly; otherwise N/A | N/A: no duration requested | +| Autoreview for non-trivial implementation changes | yes | 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 | Dirty local review clean; no accepted/actionable findings, overall 0.99 correct | +| Goal plan complete | yes | Run `node .agents/skills/autogoal/scripts/check-complete.mjs docs/plans/466-fix-procedure-name-codegen-merge-conflicts.md` | Final checker passes before closeout commit | +| Public API / package boundary proof | yes | Source-audit public API, exports, and package boundary impact | No export or type signature changes; only generated formatting and stale-map runtime diagnostic | +| Convex bundle/import proof | yes | Audit affected function-entry static graphs or record N/A | No imports added to `procedure-name.ts`; existing server entry graph remains unchanged | +| CLI/scaffold/generated proof | yes | Prove command contract and regenerate owned output or record N/A | Deterministic codegen test plus owner fixture sync/check passed | +| Release artifact classification | yes | Record whether the change is published package behavior/API/types/config/runtime or no published user-visible delta | Published package codegen/runtime behavior: patch | +| Published package changeset | yes | If published package users see a delta, load `changeset` and add/update one `.changeset/*.md` per package | Changeset skill loaded; `calm-otters-merge.md` targets `kitcn` patch and `changeset status` resolves 0.33.5 | +| No release artifact | no | If no artifact is needed, record the exact reason: internal-only, docs-only, agent-only, test-only, or no user-visible delta from `main` | N/A: published delta has a patch changeset | +| Package typecheck/build/test | yes | Run owning package checks or record N/A with reason | Package build, root typecheck, 132 owning tests, and `bun check` pass | +| Fixture/scaffold generation | yes | Run `bun run fixtures:sync` and `bun run fixtures:check` when scaffold output changed, otherwise N/A | Sync/check pass; six generated lookup fixtures changed | +| Docs/package skill sync | no | Synchronize current-state public guidance or record N/A | N/A: no public guidance change | + +Phase / pass table: +| Phase | Status | Evidence | Next | +|-------|--------|----------|------| +| Intake and source read | complete | issue, doctrine, solution, and Convex source read; claims challenged | implementation | +| Implementation | complete | multiline serializer, deduplicated stale-map diagnostic, focused tests, generated fixtures, changeset | verification | +| Verification | complete | focused red-green proof, 132 owning tests, package build, fixture sync/check, typecheck, lint, zero slop delta, clean autoreview, full `bun check` | commit and PR | +| Commit / PR / GitHub sync | complete | commit `bc59c3cd`, PR #471, verified task body, and verified issue QA comment | closeout | +| Closeout | complete | final plan checker, remote-head verification, and native goal completion | final response | + +Findings: +- Issue #466 has no comments, attachments, or open PR referencing it. +- Source evidence names the serializer and exact-line lookup owners; the report does not prove that a position-free registry can identify a builder call before export binding. +- `procedure-name.ts` captures the builder callsite once at definition time; generated runtime registries contain function references for callers but are not available to identify the registered function object while the builder constructs it. +- Local Convex source confirms registration returns a registered function without `Symbol.for("functionName")`; only generated/reference proxies expose that symbol. Dropping positions would therefore remove automatic name inference rather than simplify it. +- Existing builder integration tests already create real temporary modules and generated lookup registration, so they are the honest stale-line warning harness; the existing codegen integration test owns generated file text. +- Local Convex bundler source hard-defines `process.env.NODE_ENV` to `"production"` for function bundles, including local development; a NODE_ENV-gated warning would be dead code. The diagnostic must instead be always-on for the impossible/stale state and deduplicated once per module. + +Decisions and tradeoffs: +- Treat the first two suggested fixes as mandatory acceptance candidates and the third as an architectural alternative -> keeps the task bounded while still challenging the best owner -> may be revised if source audit disproves the current ownership model. +- Reject the position-free redesign for this task -> the construction-time function object has no export binding or Convex function-name symbol, while the separate generated caller registry is downstream-only -> positions remain necessary until Convex or builder registration exposes stable identity. +- Use an always-on, once-per-module warning rather than a NODE_ENV gate -> Convex erases the local/production distinction at bundle time, while the warning only occurs when generated state contradicts the executing module -> deployed stale maps remain visible without log floods. + +Implementation notes: +- `emitProcedureNameLookupLiteral` emits an indented entry plus trailing comma on its own physical line inside each module array. +- `inferProcedureNameFromCallsite` warns once per module when generated entries exist but none match the captured line; it still returns `undefined` and preserves explicit `.name()` / Convex symbol precedence. +- Added a patch changeset at `.changeset/calm-otters-merge.md`. + +Review fixes: +- None. Dirty-local autoreview completed with no accepted/actionable findings; overall assessment `patch is correct (0.99)`. + +Error attempts: +| Error / failed attempt | Count | Next different move | Resolution | +|------------------------|-------|---------------------|------------| +| Added the second stale procedure to the preceding valid fixture by matching an overly broad test-source hunk | 1 | Inspect the exact test slice and move the line into the stale fixture | Corrected; both stale-warning tests pass | +| Ran root typecheck concurrently with fixture verification, whose package rebuild temporarily cleaned `packages/kitcn/dist` | 1 | Let fixture generation finish, then rerun the exact typecheck alone | Standalone `bun typecheck` passed; no install corruption or source fault | +| Passed a backticked QA command through an interpolated shell argument, which executed it and truncated the issue comment | 1 | Edit the same comment from a body file, then read it back | Comment #5682762238 now contains the exact `kitcn codegen` text and both QA steps | + +Verification evidence: +- 🔴 2026-09-15: focused codegen test failed as expected: two same-module procedures produced one physical entry line (`Expected length: 2`, `Received length: 1`). +- 🟢 2026-09-15: the same focused codegen test passed after multiline emission. +- 🔴 2026-09-15: focused builder integration test confirmed stale entry behavior returns `name: undefined` and emitted 0 warnings (`Expected: 1`). +- 🟢 2026-09-15: stale-entry integration passes, emits exactly one actionable warning for two missed procedures in the same module, and preserves `name: undefined`. +- 🟢 2026-09-15: an untracked module with no generated entries emits no warning. +- 🟢 2026-09-15: `bun --cwd packages/kitcn build` passed. +- 🟢 2026-09-15: `bun run fixtures:sync` regenerated exactly six procedure-name lookup fixtures; `bun run fixtures:check` passed all eight fixture variants. +- 🟢 2026-09-15: standalone `bun typecheck` passed after the invalid concurrent build/typecheck attempt completed. +- 🟢 2026-09-15: `bun lint:fix` passed and `bun run lint:slop:delta` reports zero occurrence or score changes after consolidating test setup. +- 🟢 2026-09-15: full owning suites passed: 132 tests, 0 failures, 633 assertions across `codegen.test.ts` and `builder.test.ts`. +- 🟢 2026-09-15: `.agents/skills/autoreview/scripts/autoreview --mode local` passed secret scan and reported no accepted/actionable findings; overall `patch is correct (0.99)`. +- 🟢 2026-09-15: full `bun check` passed lint, typecheck, tests, CLI/Concave lanes, all eight fresh fixture comparisons, and runtime scenarios. +- 🟢 2026-09-15: `bunx changeset status` resolves `calm-otters-merge` as a `kitcn` patch from 0.33.4 to 0.33.5. + +Source-listed case matrix: +| Case | Source claim | Harness | Before | Expected after | Evidence | Status | +| --- | --- | --- | --- | --- | --- | --- | +| Merge-local generated output | Each procedure location in a module is emitted on its own physical line so unrelated additions do not rewrite/conflict with the entire module line | Focused codegen output test using multiple entries | 🔴 Focused test received 1 matching physical line instead of 2 | One entry per physical line with deterministic ordering and valid TypeScript | `bun test packages/kitcn/src/cli/codegen.test.ts --test-name-pattern 'generateMeta emits server-side procedure name lookup registration'` -> 1 pass | fixed | +| Loud stale same-module miss | A callsite in a module that has generated entries but no exact line match returns no inferred name without any signal | Focused procedure-name behavior tests with captured diagnostic | 🔴 Lookup returned `undefined` and warning spy received 0 calls | Lookup remains unresolved but emits one actionable warning once per module; absent modules do not warn | `bun test packages/kitcn/src/server/builder.test.ts --test-name-pattern 'middleware (warns when|does not warn when)'` -> 2 pass | fixed | +| Position-free redesign | Export-name registry may make positions unnecessary | Source audit of registration/callsite ownership and generated registry access | Construction-time builder lacks its eventual export binding | Explicit accept/reject decision without compatibility debris | Local Convex `registration_impl.ts` and `api.ts`; kitcn builder/registry source audit | rejected: positions remain required | + +Final handoff contract: +- Commit line: `bc59c3cd fix: harden generated procedure names` +- PR line: [#471 fix(codegen): make procedure names merge-local](https://github.com/udecode/kitcn/pull/471) +- Issue line: [#466](https://github.com/udecode/kitcn/issues/466) synced with verified QA comment +- Confidence line: 🟢 95-100% confidence +- Flow table: + - Reproduced: 🔴 codegen emitted two same-module procedures on one physical line; stale same-module lookup emitted zero warnings; browser ➖ N/A + - Verified: 🟢 focused cases, 132 owning tests, package build, fixtures, typecheck/lint, autoreview, and full `bun check`; browser ➖ N/A +- Browser check: ➖ N/A: generated TypeScript and server runtime only +- Outcome: procedure entries are independently mergeable and stale known-module maps emit one actionable regeneration warning +- Caveat: Convex hard-defines NODE_ENV to production, so the impossible-state warning is always-on and once-per-module; absent modules stay silent +- Design: + - Chosen boundary: CLI lookup serializer for diff locality; server callsite lookup for stale-state diagnosis + - Why not quick patch: conflict resolution alone can retain a stale/incomplete generated map and preserves the whole-line conflict surface + - Why not broader change: builder construction has no eventual export binding or Convex function-name symbol, so removing positions would remove automatic inference +- Verified: TDD red-green, 132 owner tests, build, eight fixtures, typecheck, lint, zero slop delta, changeset status, clean autoreview, and full repo check +- PR body verified: `gh pr view 471 --repo udecode/kitcn --json body` confirms the required task format and auto-release block with no self-link + +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 accepted PR #270 visual format. The body starts with an emoji + issue/fix line, for example `🐛 Fixes #123` or `🐛 Fixes ➖ N/A`, then + `🧭 Task plan: docs/plans/.md`, 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, 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. + +Final handoff / sync: +- Commit: `bc59c3cd fix: harden generated procedure names` plus final plan closeout commit +- PR: [#471](https://github.com/udecode/kitcn/pull/471), open against `main` +- Issue: [#466 QA comment](https://github.com/udecode/kitcn/issues/466#issuecomment-5682762238) read back exactly +- Browser proof: N/A: no browser-rendered behavior +- Caveats: warning is always-on for a known stale module and deduplicated once per module because Convex erases NODE_ENV distinction + +Timeline: +- 2026-09-15T14:40:54.312Z Task goal plan created. +- 2026-09-15T14:41Z Read issue #466, comments, task/autogoal/TDD/changeset skills, `VISION.md`, and docs ownership; created active goal and dedicated branch. +- 2026-09-15T15:03Z Focused red-green, full owner tests, package build, fixtures, typecheck, lint, zero slop delta, and autoreview passed. +- 2026-09-15T17:10Z Full `bun check` passed; committed and pushed the entire checkout, opened PR #471, verified its task body, and synced issue #466 with QA. + +Reboot status: +| Question | Answer | +|----------|--------| +| Where am I? | Closeout complete | +| Where am I going? | Final response | +| What is the goal? | Resolve the generated lookup merge-conflict and stale-miss safety cases, verify the package/repo, review cleanly, and ship one dedicated PR | +| What have I learned? | Position lookup is still required at builder construction time; Convex hard-defines NODE_ENV to production, so the stale-state warning must be always-on and deduplicated | +| What have I done? | Implemented and proved both bounded fixes, passed every package/repo/review gate, opened PR #471, and read back the PR/issue sync | + +Open risks: +- The warning is intentionally emitted in deployed bundles when a generated map contains the module but misses the callsite; once-per-module deduplication bounds noise, and absent modules stay silent. +- CI may still run independently on PR #471; local full `bun check` and autoreview are green. + +Hard closeout guard: +- A local-only final response for verified code-changing work is invalid unless + this plan records an explicit user decline, no local patch, analytical/ + blocked/inconclusive outcome, or a real commit/PR blocker. diff --git a/fixtures/expo-auth/convex/functions/generated/procedure-names.gen.ts b/fixtures/expo-auth/convex/functions/generated/procedure-names.gen.ts index 5766e1c10..750539132 100644 --- a/fixtures/expo-auth/convex/functions/generated/procedure-names.gen.ts +++ b/fixtures/expo-auth/convex/functions/generated/procedure-names.gen.ts @@ -3,5 +3,8 @@ // Do not edit manually. Run `kitcn codegen` to regenerate. export const procedureNames = { - "messages.ts": [{ column: 3, line: 32, name: "messages:create" }, { column: 3, line: 15, name: "messages:list" }], + "messages.ts": [ + { column: 3, line: 32, name: "messages:create" }, + { column: 3, line: 15, name: "messages:list" }, + ], }; diff --git a/fixtures/expo/convex/functions/generated/procedure-names.gen.ts b/fixtures/expo/convex/functions/generated/procedure-names.gen.ts index 5766e1c10..750539132 100644 --- a/fixtures/expo/convex/functions/generated/procedure-names.gen.ts +++ b/fixtures/expo/convex/functions/generated/procedure-names.gen.ts @@ -3,5 +3,8 @@ // Do not edit manually. Run `kitcn codegen` to regenerate. export const procedureNames = { - "messages.ts": [{ column: 3, line: 32, name: "messages:create" }, { column: 3, line: 15, name: "messages:list" }], + "messages.ts": [ + { column: 3, line: 32, name: "messages:create" }, + { column: 3, line: 15, name: "messages:list" }, + ], }; diff --git a/fixtures/next-auth/convex/functions/generated/procedure-names.gen.ts b/fixtures/next-auth/convex/functions/generated/procedure-names.gen.ts index 5766e1c10..750539132 100644 --- a/fixtures/next-auth/convex/functions/generated/procedure-names.gen.ts +++ b/fixtures/next-auth/convex/functions/generated/procedure-names.gen.ts @@ -3,5 +3,8 @@ // Do not edit manually. Run `kitcn codegen` to regenerate. export const procedureNames = { - "messages.ts": [{ column: 3, line: 32, name: "messages:create" }, { column: 3, line: 15, name: "messages:list" }], + "messages.ts": [ + { column: 3, line: 32, name: "messages:create" }, + { column: 3, line: 15, name: "messages:list" }, + ], }; diff --git a/fixtures/next/convex/functions/generated/procedure-names.gen.ts b/fixtures/next/convex/functions/generated/procedure-names.gen.ts index 5766e1c10..750539132 100644 --- a/fixtures/next/convex/functions/generated/procedure-names.gen.ts +++ b/fixtures/next/convex/functions/generated/procedure-names.gen.ts @@ -3,5 +3,8 @@ // Do not edit manually. Run `kitcn codegen` to regenerate. export const procedureNames = { - "messages.ts": [{ column: 3, line: 32, name: "messages:create" }, { column: 3, line: 15, name: "messages:list" }], + "messages.ts": [ + { column: 3, line: 32, name: "messages:create" }, + { column: 3, line: 15, name: "messages:list" }, + ], }; diff --git a/fixtures/start-auth/convex/functions/generated/procedure-names.gen.ts b/fixtures/start-auth/convex/functions/generated/procedure-names.gen.ts index 5766e1c10..750539132 100644 --- a/fixtures/start-auth/convex/functions/generated/procedure-names.gen.ts +++ b/fixtures/start-auth/convex/functions/generated/procedure-names.gen.ts @@ -3,5 +3,8 @@ // Do not edit manually. Run `kitcn codegen` to regenerate. export const procedureNames = { - "messages.ts": [{ column: 3, line: 32, name: "messages:create" }, { column: 3, line: 15, name: "messages:list" }], + "messages.ts": [ + { column: 3, line: 32, name: "messages:create" }, + { column: 3, line: 15, name: "messages:list" }, + ], }; diff --git a/fixtures/start/convex/functions/generated/procedure-names.gen.ts b/fixtures/start/convex/functions/generated/procedure-names.gen.ts index 5766e1c10..750539132 100644 --- a/fixtures/start/convex/functions/generated/procedure-names.gen.ts +++ b/fixtures/start/convex/functions/generated/procedure-names.gen.ts @@ -3,5 +3,8 @@ // Do not edit manually. Run `kitcn codegen` to regenerate. export const procedureNames = { - "messages.ts": [{ column: 3, line: 32, name: "messages:create" }, { column: 3, line: 15, name: "messages:list" }], + "messages.ts": [ + { column: 3, line: 32, name: "messages:create" }, + { column: 3, line: 15, name: "messages:list" }, + ], }; diff --git a/packages/kitcn/src/cli/codegen.test.ts b/packages/kitcn/src/cli/codegen.test.ts index e8c43ec52..d9692cd60 100644 --- a/packages/kitcn/src/cli/codegen.test.ts +++ b/packages/kitcn/src/cli/codegen.test.ts @@ -244,6 +244,7 @@ describe('cli/codegen', () => { import { publicQuery } from './lib/crpc'; export const list = publicQuery.query(async () => []); + export const count = publicQuery.query(async () => 0); `.trim() ); @@ -270,6 +271,12 @@ describe('cli/codegen', () => { expect(generatedProcedureNames).toContain('export const procedureNames'); expect(generatedProcedureNames).toContain('"todos.ts"'); expect(generatedProcedureNames).toContain('"todos:list"'); + expect(generatedProcedureNames).toContain('"todos:count"'); + expect( + generatedProcedureNames + .split('\n') + .filter((line) => line.includes('name: "todos:')) + ).toHaveLength(2); } finally { process.chdir(oldCwd); } diff --git a/packages/kitcn/src/cli/codegen.ts b/packages/kitcn/src/cli/codegen.ts index 3796a0306..889fb7825 100644 --- a/packages/kitcn/src/cli/codegen.ts +++ b/packages/kitcn/src/cli/codegen.ts @@ -300,11 +300,11 @@ function emitProcedureNameLookupLiteral(lookup: ProcedureNameLookup): string { const items = locations .map( (location) => - `{ column: ${location.column}, line: ${location.line}, name: ${JSON.stringify(location.name)} }` + ` { column: ${location.column}, line: ${location.line}, name: ${JSON.stringify(location.name)} },` ) - .join(', '); + .join('\n'); - return ` ${JSON.stringify(file)}: [${items}],`; + return ` ${JSON.stringify(file)}: [\n${items}\n ],`; }) .join('\n'); diff --git a/packages/kitcn/src/server/builder.test.ts b/packages/kitcn/src/server/builder.test.ts index 02bdd1d9b..72254ca47 100644 --- a/packages/kitcn/src/server/builder.test.ts +++ b/packages/kitcn/src/server/builder.test.ts @@ -15,6 +15,7 @@ import { z } from 'zod'; import { encodeWire } from '../crpc/transformer'; import { initCRPC } from './builder'; import { CRPCError } from './error'; +import type { ProcedureNameLookup } from './procedure-name'; function getLocationForMarker(source: string, marker: string) { const index = source.indexOf(marker); @@ -31,6 +32,63 @@ function getLocationForMarker(source: string, marker: string) { }; } +async function importProcedureNameFixture(params: { + fileName: string; + functionsDirHint: string; + lookup: ProcedureNameLookup; + source: string; +}) { + const dir = fs.mkdtempSync( + path.join(os.tmpdir(), 'kitcn-procedure-name-fixture-') + ); + const functionsDir = path.join(dir, params.functionsDirHint); + const filePath = path.join(functionsDir, params.fileName); + const serverUrl = pathToFileURL( + path.join(process.cwd(), 'packages/kitcn/src/server/index.ts') + ).href; + + fs.mkdirSync(path.join(functionsDir, 'generated'), { recursive: true }); + fs.symlinkSync( + path.join(process.cwd(), 'node_modules'), + path.join(dir, 'node_modules'), + 'dir' + ); + fs.writeFileSync( + path.join(functionsDir, 'generated', 'server.ts'), + ` + import { + initCRPC as baseInitCRPC, + registerProcedureNameLookup, + } from ${JSON.stringify(serverUrl)}; + + registerProcedureNameLookup( + ${JSON.stringify(params.lookup, null, 2)}, + ${JSON.stringify(params.functionsDirHint)} + ); + + export const initCRPC = baseInitCRPC; + ` + ); + fs.writeFileSync(filePath, params.source); + + return await import(`${pathToFileURL(filePath).href}?t=${Date.now()}`); +} + +const captureConsoleWarnings = () => { + const originalWarn = console.warn; + const warnings: unknown[][] = []; + console.warn = (...args: unknown[]) => { + warnings.push(args); + }; + + return { + restore: () => { + console.warn = originalWarn; + }, + warnings, + }; +}; + describe('server/builder', () => { test('create() with no args exposes full procedure surface', () => { const c = initCRPC.create(); @@ -209,12 +267,6 @@ describe('server/builder', () => { }); test('middleware infers procedure info from exported module path by default', async () => { - const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'kitcn-procedure-name-')); - const functionsDir = path.join(dir, 'convex', 'functions'); - const filePath = path.join(functionsDir, 'posts.ts'); - const serverUrl = pathToFileURL( - path.join(process.cwd(), 'packages/kitcn/src/server/index.ts') - ).href; const source = ` import { queryGeneric, internalQueryGeneric } from 'convex/server'; import { initCRPC } from './generated/server'; @@ -238,59 +290,69 @@ describe('server/builder', () => { .query(async () => 'ok'); `; const location = getLocationForMarker(source, ".query(async () => 'ok')"); + const mod = await importProcedureNameFixture({ + fileName: 'posts.ts', + functionsDirHint: 'convex/functions', + lookup: { + 'posts.ts': [ + { + column: location.column, + line: location.line, + name: 'posts:list', + }, + ], + }, + source, + }); - fs.mkdirSync(functionsDir, { recursive: true }); - fs.mkdirSync(path.join(functionsDir, 'generated'), { recursive: true }); - fs.symlinkSync( - path.join(process.cwd(), 'node_modules'), - path.join(dir, 'node_modules'), - 'dir' - ); - fs.writeFileSync( - path.join(dir, 'convex.json'), - `${JSON.stringify({ functions: 'convex/functions' }, null, 2)}\n` - ); - fs.writeFileSync( - path.join(functionsDir, 'generated', 'server.ts'), - ` - import { - initCRPC as baseInitCRPC, - registerProcedureNameLookup, - } from ${JSON.stringify(serverUrl)}; - - registerProcedureNameLookup( - { - 'posts.ts': [ - { - column: ${location.column}, - line: ${location.line}, - name: 'posts:list', - }, - ], - }, - 'convex/functions' - ); + await expect((mod as any).list._handler({}, {})).resolves.toBe('ok'); + expect((mod as any).seen).toEqual([{ type: 'query', name: 'posts:list' }]); + }); - export const initCRPC = baseInitCRPC; - ` - ); - fs.writeFileSync(filePath, source); + test('middleware infers procedure info with default convex root when convex.json is absent', async () => { + const source = ` + import { queryGeneric, internalQueryGeneric } from 'convex/server'; + import { initCRPC } from './generated/server'; + + export const seen = []; + + const c = initCRPC + .context({ + query: () => ({ userId: null }), + }) + .create({ + query: queryGeneric, + internalQuery: internalQueryGeneric, + }); - const mod = await import(`${pathToFileURL(filePath).href}?t=${Date.now()}`); + export const list = c.query + .use(async ({ ctx, procedure, next }) => { + seen.push(procedure); + return next({ ctx }); + }) + .query(async () => 'ok'); + `; + const location = getLocationForMarker(source, ".query(async () => 'ok')"); + const mod = await importProcedureNameFixture({ + fileName: 'posts.ts', + functionsDirHint: 'convex', + lookup: { + 'posts.ts': [ + { + column: location.column, + line: location.line, + name: 'posts:list', + }, + ], + }, + source, + }); await expect((mod as any).list._handler({}, {})).resolves.toBe('ok'); expect((mod as any).seen).toEqual([{ type: 'query', name: 'posts:list' }]); }); - test('middleware infers procedure info with default convex root when convex.json is absent', async () => { - const dir = fs.mkdtempSync( - path.join(os.tmpdir(), 'kitcn-procedure-name-default-root-') - ); - const functionsDir = path.join(dir, 'convex'); - const filePath = path.join(functionsDir, 'posts.ts'); - const serverUrl = pathToFileURL( - path.join(process.cwd(), 'packages/kitcn/src/server/index.ts') - ).href; + test('middleware warns when a generated procedure name entry is stale', async () => { const source = ` import { queryGeneric, internalQueryGeneric } from 'convex/server'; import { initCRPC } from './generated/server'; @@ -312,46 +374,77 @@ describe('server/builder', () => { return next({ ctx }); }) .query(async () => 'ok'); + + export const count = c.query.query(async () => 1); `; const location = getLocationForMarker(source, ".query(async () => 'ok')"); - fs.mkdirSync(functionsDir, { recursive: true }); - fs.mkdirSync(path.join(functionsDir, 'generated'), { recursive: true }); - fs.symlinkSync( - path.join(process.cwd(), 'node_modules'), - path.join(dir, 'node_modules'), - 'dir' - ); - fs.writeFileSync( - path.join(functionsDir, 'generated', 'server.ts'), - ` - import { - initCRPC as baseInitCRPC, - registerProcedureNameLookup, - } from ${JSON.stringify(serverUrl)}; - - registerProcedureNameLookup( - { - 'posts.ts': [ + const warningCapture = captureConsoleWarnings(); + try { + const mod = await importProcedureNameFixture({ + fileName: 'stale-posts.ts', + functionsDirHint: 'convex/functions', + lookup: { + 'stale-posts.ts': [ { - column: ${location.column}, - line: ${location.line}, - name: 'posts:list', + column: location.column, + line: location.line + 1, + name: 'stale-posts:list', }, ], }, - 'convex' - ); + source, + }); - export const initCRPC = baseInitCRPC; - ` - ); - fs.writeFileSync(filePath, source); + await expect((mod as any).list._handler({}, {})).resolves.toBe('ok'); + await expect((mod as any).count._handler({}, {})).resolves.toBe(1); + expect((mod as any).seen).toEqual([{ type: 'query', name: undefined }]); + expect(warningCapture.warnings).toHaveLength(1); + expect(warningCapture.warnings[0]?.[0]).toContain('Run `kitcn codegen`'); + } finally { + warningCapture.restore(); + } + }); - const mod = await import(`${pathToFileURL(filePath).href}?t=${Date.now()}`); + test('middleware does not warn when its module has no generated entries', async () => { + const source = ` + import { queryGeneric, internalQueryGeneric } from 'convex/server'; + import { initCRPC } from './generated/server'; - await expect((mod as any).list._handler({}, {})).resolves.toBe('ok'); - expect((mod as any).seen).toEqual([{ type: 'query', name: 'posts:list' }]); + export const seen = []; + + const c = initCRPC + .context({ query: () => ({ userId: null }) }) + .create({ + query: queryGeneric, + internalQuery: internalQueryGeneric, + }); + + export const list = c.query + .use(async ({ ctx, procedure, next }) => { + seen.push(procedure); + return next({ ctx }); + }) + .query(async () => 'ok'); + `; + + const warningCapture = captureConsoleWarnings(); + try { + const mod = await importProcedureNameFixture({ + fileName: 'untracked-posts.ts', + functionsDirHint: 'convex/functions', + lookup: { + 'other.ts': [{ column: 1, line: 1, name: 'other:list' }], + }, + source, + }); + + await expect((mod as any).list._handler({}, {})).resolves.toBe('ok'); + expect((mod as any).seen).toEqual([{ type: 'query', name: undefined }]); + expect(warningCapture.warnings).toHaveLength(0); + } finally { + warningCapture.restore(); + } }); test('input schemas are merged when chained', async () => { diff --git a/packages/kitcn/src/server/procedure-name.ts b/packages/kitcn/src/server/procedure-name.ts index 0cff5fa6b..3cdf2fc38 100644 --- a/packages/kitcn/src/server/procedure-name.ts +++ b/packages/kitcn/src/server/procedure-name.ts @@ -14,6 +14,7 @@ type StackFrameLike = { const LOOKUP_KEY = '__KITCN_PROCEDURE_NAME_LOOKUP__'; const HINTS_KEY = '__KITCN_PROCEDURE_NAME_HINTS__'; +const WARNED_MISSES_KEY = '__KITCN_PROCEDURE_NAME_WARNED_MISSES__'; const PATH_SEPARATOR_RE = /\\/g; const TRIM_SLASHES_RE = /^\/+|\/+$/g; const PACKAGE_FRAME_MARKERS = ['/node_modules/kitcn/', '/packages/kitcn/']; @@ -64,6 +65,19 @@ function getGlobalHints(): string[] { return hints; } +function getGlobalWarnedMisses(): Set { + const globalScope = globalThis as Record; + const existing = globalScope[WARNED_MISSES_KEY]; + + if (existing instanceof Set) { + return existing as Set; + } + + const warnedMisses = new Set(); + globalScope[WARNED_MISSES_KEY] = warnedMisses; + return warnedMisses; +} + export function registerProcedureNameLookup( lookup: ProcedureNameLookup, functionsDirHint: string @@ -182,6 +196,21 @@ function findBestEntry( }); } +function warnAboutStaleLookup( + relativeFilePath: string, + location: SourceLocation +): void { + const warnedMisses = getGlobalWarnedMisses(); + if (warnedMisses.has(relativeFilePath)) { + return; + } + + warnedMisses.add(relativeFilePath); + console.warn( + `kitcn could not infer a procedure name at ${relativeFilePath}:${location.line} because generated/procedure-names.gen.ts has no matching entry. Run \`kitcn codegen\` to regenerate it.` + ); +} + export function inferProcedureNameFromCallsite(): string | undefined { const location = captureCallsite(); if (!location) { @@ -198,5 +227,11 @@ export function inferProcedureNameFromCallsite(): string | undefined { return; } - return findBestEntry(entries, location)?.name; + const entry = findBestEntry(entries, location); + if (!entry) { + warnAboutStaleLookup(relativeFilePath, location); + return; + } + + return entry.name; }