fix(context,impact): bug-report intent, named-repo scoping, UI-page required owners - #240
Merged
Merged
Conversation
… multi-repo queries, stop excluding UI pages from required owners Root-caused against a real cross-repo review (bashbop-api/mobile-app/event-web ticket-scan and date-display fixes) that otito scored itself: - context-engine: a query with no verb from actionWords (e.g. "... bugs in the mobile app") came back with intent "unknown" and the ambiguous-action open question, even though "bugs" is an unambiguous debug signal. Add a debug-synonym set (bug/bugs/broken/crash/regression/...). - context-engine: "mobile" and "app" are stopWords for content scoring (too generic to match file text with), so a multi-repo query naming one repo by a word from its own folder name had that signal silently discarded, and a larger sibling repo's hotspots dominated primaryFiles. Add computeRepoHints: when 2+ repos are queried and the raw query names one by a discriminating folder-name segment, boost that repo's files and softly demote the rest. - impact: REQUEST_BOUNDARY_KINDS gated `route` (a Next.js page.tsx/layout.tsx, a rendered UI screen) behind the same "does the query use an API word" check meant for actual request-boundary kinds (apiRoute/controller/dto). A page-deprecation request naturally uses no API vocabulary, so the changed, top-scored page.tsx was excluded from requiredOwners while unrelated components that merely shared a word became "required" instead. Drop `route` from the set; `apiRoute` already covers real API endpoints. - impact: ported context-engine's IDF-style tokenWeightFactor/ computeTokenDocFrequency dampening (a query term that recurs across most of the repo counts for less) to impact.js's path/symbol/export/import/route matching, which never had it. - impact: genericOwnerFallback (the pool for `source`-kind owners like *.util.ts) only ran when no conventional owner kind matched the query at all, so a strong utility-file owner was never even considered once any controller/dto/component also matched generically. Merge the two pools and let files compete on score instead of treating the fallback as last resort. Regression tests added: tests/context-engine.test.js (debug-intent inference, repo-hint boost with an unhinted control and a single-repo no-op check), tests/impact.test.js (tokenWeightFactor/computeTokenDocFrequency unit test, UI-page-route required-owner, controller still boundary-gated, source-kind vs conventional-kind owner-pool merge).
Collaborator
Author
Agent Experience (AX) before/afterMeasured with
Containment improves because fewer false-positive owners are pulled in. Clarity stays at 20 for the API and web queries: the concept vocabulary still infers no concepts for the booking/ticket domain (left as a follow-up in the description). |
Merged
16 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Otito was used today to review a real cross-repo fix (bashbop-api PR #527, bashbop-mobile-app PR #21, bashbop-event-web PR #590 — ticket-scan/QR check-in + date-timezone display bugs). This PR fixes the three ranking/intent gaps that session found, root-caused against otito's own source, and adds regression tests that reproduce each gap and prove the fix.
npm run skills:checkfails identically on a cleanorigin/maincheckout — pre-existing, unrelated to this change, not touched here.Base branch note:
origin/developexists but is a strict ancestor oforigin/main(0 commits ahead, 6 behind — all "Merge pull request # from BASHBOP/develop" merges that never made it back ontodevelop). Branching from or targeting the staledevelopwould pull in an unrelated 6-commit delta and risk conflicts, so this PR is branched from and targetsmain, the actually up-to-date integration branch. Flagging this in casedevelopis meant to be kept current.Gaps found, evidence, root cause, fix status
context_pack("...bugs in the mobile app", paths:[mobile,api])→intent.action: "unknown", open question "requested action is ambiguous"inferIntentonly recognizes verbs inactionWords(add/build/.../review/test/update); a symptom-framed query ("... bugs") never names one"mobile"and"app"are in context-engine'sstopWords(too generic for content matching), so the one explicit repo-scoping word in the query was silently discarded before scoring ever saw itchange_impacton bashbop-event-web, "deprecate web scan-ticket page..." →app/dashboard/scan-ticket/page.tsx(top-scored, actually-changed) ranked "advisory";MobileTicketButton.tsx/TicketPurchaseDialog.tsx(weak "ticket" overlap, not actually changed) became "required"REQUEST_BOUNDARY_KINDSincludesroute, code-map's kind for a Next.jspage.tsx/layout.tsx(a UI screen), and gates required-owner candidacy behind literal API vocabulary (api/endpoint/form/payload/request/route/submit) that a page-deprecation request naturally never useschange_impacton bashbop-api, multi-clause ticket/mobile/web query →organizer-ticket-sales.controller.ts/.dto.ts(unrelated "ticket sales" reporting) ranked as "required owners";booking.controller.ts(actually changed) ranked 7th as merely "supporting"; a long tail of unrelatedauthentication/*files pulled in as fan-outscoreFilesums path+symbol+export+import+route hits with no per-term frequency dampening (context-engine.js already has this astokenWeightFactor/computeTokenDocFrequency; impact.js never did), so a file whose entire domain name is a generic query word (here "ticket") stacks that one weak signal across five fieldssrc/booking/utils/ticket-qr.util.ts, kindsource) never became a required owner even though it was the single highest-scored, diff-confirmed filegenericOwnerFallback(the pool that letssource/hookkind files ground a task) only runs when no conventional owner kind (controller/dto/...) matched at all — once any controller matched generically, the real utility-file owner was never even consideredInferred concepts: nonefor the bashbop-api queryCONCEPT_SYNONYMSonly covers auth/payment/data-model/request-surface/config vocabulary; a booking/ticket/date-display domain has no concept bucket/dashboard/scan-ticket(routes.ts, nav, guide,PublishChecklistCard.tsx) and the 5messages/*.jsoni18n filesmodel-route.js/the prompt hook, notcontext_pack/change_impactscoring; not investigated in this passWhat was fixed
src/lib/context-engine.jsinferIntent: adebugSynonymsset (bug/bugs/bugfix/broken/crash/crashes/crashing/regression/regressions) now yieldsintent.action: "debug"when no verb fromactionWordsis present. A query with neither still correctly reports"unknown"(regression-tested).computeRepoHints(new): when acontext_packcall spans 2+ repos and the raw query names one of them by a word unique to its folder name (discriminating segments only — a shared prefix like every Bashbop repo'sbashbop-doesn't count), that repo's files get a+40bonus and every other queried repo's files are multiplied by0.6. No-ops for single-repo calls and for a hint that would name every queried repo.src/lib/impact.jsREQUEST_BOUNDARY_KINDS: droppedroute(UI page).apiRoute(app/api/**/route.ts) already covers the actual API-boundary case;controller/dto/apiClientare untouched and still gated.computeTokenDocFrequency/tokenWeightFactor(new, ported from context-engine.js with identical thresholds and the sametotalFiles < 12neutral-on-small-repos guard): every path/symbol/export/import/route match inscoreFileis now weighted by how common that term is across the indexed repo.classifyImpactRoles:genericOwnerFallback's candidates are now merged into the conventional-owner pool (mergeOwnerCandidates, new) instead of being used only when the conventional pool is empty, so a strongsource/hook-kind owner can outrank a weaker conventional-kind one.Measured before/after (below) uses the live library against the real repos with
diffBase: origin/main, matching whatchange_impact/context_packdo internally.Gap 1 —
context_pack, mobile+api, "...bugs...in the mobile app"intent.action"unknown""debug"openQuestions["The requested action is ambiguous..."][]tickets/index.tsxonlytickets/index.tsx,hooks/useScanner.ts,lib/scanner.ts,lib/bookingTicket.ts(at limit 12, alsoapp/(tabs)/scanner.tsx)test/scanner.test.mjs,test/eventDateDisplay.test.mjstestsNot fully solved:
lib/eventDateDisplay.ts,lib/exploreFeed.ts,components/ScanResult.tsxstill don't clear the top-8/12 cut (thediversifyByDomaincap of 2 files/domain in primaryFiles is a separate, deliberate mechanism this PR did not touch).Gap 3 —
change_impact, bashbop-event-web, "deprecate web scan-ticket page..." (diffBase: origin/main)requiredOwnersMobileTicketButton.tsx,TicketPurchaseDialog.tsx,BookingTicket.tsx(none actually changed)app/dashboard/scan-ticket/page.tsx(the one actually-changed file)validation.confirmedDirect[]["app/dashboard/scan-ticket/page.tsx"]page.tsxroleadvisory(score 146, #1 by score, but excluded from required)requiredNot fixed (documented, not attempted here): the 18
missedChangedFilesinclude inbound-link files (routes.ts, nav,PublishChecklistCard.tsx) and the 5 locale JSON files — no reverse-reference/route-usage signal exists yet, and translations stay demoted by design.Gap 2 —
change_impact, bashbop-api, multi-clause query (diffBase: origin/main)requiredOwnersorganizer-ticket-sales.dto.ts,organizer-ticket-sales.controller.ts(neither changed)scan-ticket.dto.ts(not changed, false positive remains),ticket-qr.util.ts(changed — the real fix file),organizer-ticket-sales.controller.ts(not changed, false positive remains)validation.confirmedDirect[]["src/booking/utils/ticket-qr.util.ts"]booking.controller.tsscore / rolemissedChangedFilescountscan-ticket.dto.tsfalse positive now also present; the underlying set of real changed files not yet surfaced is effectively unchanged)Improved (a real changed file now confirms), but organizer-ticket-sales' "ticket sales" domain and the actual "ticket scan/check-in" domain remain lexically entangled — see "deliberately not fixed" below.
What was deliberately not fixed, and why
organizer-ticket-sales.*,scan-ticket.dto.tsas required owners; real changed files likebooking.controller.ts/events.service.ts/constants.tsstill not "required"). The IDF dampening ported here helps but isn't enough: "ticket" is still specific enough (~14% doc frequency in bashbop-api) to only get a 0.55× haircut, not enough to overcome a file whose path+symbols+exports+route all repeat it. The principled fix is porting context-engine.js's phrase-matching (extractPhrases/scorePhraseMatches— "ticket scan"/"scan ticket" as a 2–3 word unit) into impact.js, which would specifically distinguish "ticket scan" from "ticket sales" without relying on frequency alone. That's a second, similarly-sized change touching the same scoring core that every impact.js consumer (AX, model-route, convergence) depends on; bundling it here risked under-testing it under this review's time budget. Left as explicit follow-up./dashboard/scan-ticket) that context-engine.js/impact.js don't have in any form today — a bigger, separate feature, not a targeted bug fix.Inferred concepts: nonefor booking/ticket/date-display domains.CONCEPT_SYNONYMSis intentionally a small, curated vocabulary (auth/payment/data-model/request-surface/config); expanding it to every product domain risks the concept-demotion mechanism becoming noise. Left alone.model-route.js, a different code path fromcontext_pack/change_impact, out of scope for this review pass.Checks run
All from a clean checkout, in this order — baseline on
origin/mainfirst, then on this branch.Baseline (
origin/main, clean checkout, before any change):npm run format:checknpm run lintnpm run typechecknpm run version:checknpm run docs:diagram:checknpm run skills:check.cursor/skills/otito-scope/SKILL.mdand.codex/skills/otito-scope/SKILL.mddrifted fromcodex/skills. Pre-existing, unrelated to this change.npm testnpm run test:coverageThis branch (after the fix):
npm run format:checknpm run lintnpm run typechecknpm run version:checknpm run docs:diagram:checknpm run skills:checknpm testnpm run test:coverageCI note: the task brief for this review flagged that GitHub Actions on the BASHBOP org was not starting jobs due to a billing/spending-limit issue. That did not reproduce on this PR: all checks ran and passed — Docs build, Generate PR review context, Otito readiness, and Quality gates all green (
auto-mergeshows "skipping", which is expected, not a failure). See https://github.com/BASHBOP/otito/pull/240/checks.Test plan
npm run format:check/npm run lint/npm run typecheckclean on this branchnpm test— 795/795 passing (8 new regression tests reproduce each fixed gap)npm run test:coverage— thresholds metnpm run version:check/npm run docs:diagram:checkcleannpm run skills:checkfails identically to a cleanorigin/mainbaseline (pre-existing, documented, not touched)bashbop-api,bashbop-mobile-app,bashbop-event-web) withdiffBase: origin/main