Skip to content

๐Ÿงฌ repoctx Absorption Study

Date: 2026-05-29 Author: Claude (with Oluwasegun Olumbe) Status: Phase 1 implementation paused mid-flight to capture this record.

This document captures the field test, design decisions, and refined plan for absorbing impact-map (Python) and pullpass (Go) into repoctx (TypeScript/Node) so there is one local-first tool, one binary, one MCP server, and one risk vocabulary.


๐Ÿ“‹ Table of contents

  1. The three tools, briefly
  2. Decisions taken
  3. Field test โ€” bashbop-api
  4. Performance
  5. Five lessons from running them
  6. Refined absorption plan
  7. Phase 1 status
  8. Open follow-ups

๐Ÿงฐ The three tools, briefly

Tool Stack Core LOC What it does
repoctx TS/Node ~7,000 Repo indexing, AST code map, context packs, PR review, MCP server
impact-map Python ~1,200 "English change request โ†’ likely files + tests + risks"
pullpass Go ~2,500 "Can this PR merge?" โ†’ PASS/WARN/FAIL with policy profiles

Key observation discovered while reading the source: pullpass's local evaluator already shells out to repoctx context and repoctx pr as its "Context Evidence" (pullpass/internal/local/evaluate.go:65-70). The dependency arrow already points toward repoctx. Absorption is reversing a relationship that is halfway there.


โœ… Decisions taken

Question Choice Rationale
Absorption mode Port logic to TypeScript One install, one binary, one MCP server. Kills cross-runtime friction.
Standalone repos Archive after migration Avoid dual maintenance. Existing installs keep working; READMEs point to repoctx.

Output style

User requested "very fancy and nicely formatted with emojis etc." โ†’ the new renderer (src/lib/render/fancy.js) becomes the default; plain mode via --no-emoji (or NO_EMOJI=1) for CI logs.


๐Ÿ”ฌ Field test โ€” bashbop-api

Repo: /Users/segzy/projects/bashbop-api (NestJS, Prisma, Stripe SDK, 3,140 source-like files, payment-heavy).

๐ŸŽฏ Query 1 โ€” "add Stripe refunds to bookings"

Rank ๐Ÿ impact-map ๐Ÿ“ฆ repoctx context
1 โŒ documentation/styles/stripe.css (score 128) โœ… scripts/sync-database-with-stripe.ts (50)
2 โŒ scripts/check-orphaned-bookings-in-stripe.js (119) โœ… src/guests/dto/guest.update.dto.ts (34)
3 โœ… src/booking/booking.controller.ts (112) ๐ŸŽฏ src/payment/processors/stripe.processor.ts (34)
4 โŒ documentation/controllers/StripeController.html (102) โœ… src/booking/booking.controller.ts (31)
5 โŒ src/scripts/stripe-db-sync-matcher.js (100) โ€”

๐Ÿšจ impact-map ranked a generated CSS file as the #1 owner of "add Stripe refunds." The real owner stripe.processor.ts appears in repoctx's top 3 but not in impact-map's top 8.

Why it happened โ€” scoring.py:170 gives path matches: stripe +9 per token, plus a +4 "configuration/domain hint" because stripe is in CONFIG_HINTS, plus an +88 import-graph boost from sibling files. No domain or kind awareness penalises documentation/ or .css.

๐ŸŽฏ Query 2 โ€” "fix Apple sign-in token validation"

Rank ๐Ÿ impact-map ๐Ÿ“ฆ repoctx context
1 โŒ src/shared/validation/currency-validation.service.ts (49) โŒ src/shared/validation/currency-validation.service.ts (59)
2 โŒ documentation/injectables/CurrencyValidationService.html (35) ๐ŸŽฏ src/authentication/auth.controller.ts (50)
3 โŒ documentation/interfaces/WebhookValidationResult.html (35) โœ… src/guests/guest.controller.ts (28)
4 โŒ documentation/interfaces/CurrencyValidationResult.html (34) โœ… src/utils/pipes/sanitizing-validation.pipe.ts (25)

Both tools overweight "validation". repoctx recovers with the auth controller at #2; impact-map's top 4 is dominated by generated HTML docs.

๐Ÿ›ก๏ธ pullpass โ€” auth + Prisma migration diff (HEAD~5)

Verdict: WARN
โœ… Changed files          9 files
โœ… Secret safety          no secrets touched
โš ๏ธ  Risk review           5 sensitive paths (prisma/*, auth.controller.ts, config schema)
โœ… Release discipline     no version bump expected
โœ… Validation commands    yarn test ยท yarn lint ยท yarn check:type
โœ… Dependency audit       commands available
โš ๏ธ  Review state          local mode can't verify approvals
โœ… Policy profile         standard

๐Ÿงช repoctx pr โ€” same diff

Risk: high (11)
Changed Domains: prisma (3, +2997/-1), authentication (1, +287/-0), user, config, utils, test
Risk Flags: auth/security ยท data model ยท large PR ยท large file diff ยท request surface
Review Targets: 20 auth routes mapped to auth.controller.ts
Verification: yarn lint ยท yarn check:type ยท yarn test ยท yarn test:e2e ยท yarn build

๐Ÿค Verdict: complementary, not competing. pullpass gives a clean verdict; repoctx pr gives rich context. After absorption these merge into repoctx review.


โšก Performance

Same repo, same query, cold-ish runs:

impact-map . "fix Apple sign-in token validation" --top 5 --json   โ†’   8.99s
repoctx context "fix Apple sign-in token validation" --json        โ†’   1.72s
                                                              5.2ร— faster
  • impact-map re-scans every call.
  • repoctx caches .dev-context/index.json and refreshes incrementally.

For an MCP server called repeatedly by an agent, this is a material UX win.


๐Ÿง  Five lessons from running them

1. ๐Ÿชฆ impact-map's scanner is the actual problem

The scoring formula isn't bad โ€” what kills it is the regex scanner treating .css, documentation/*.html, and one-off scripts/*.js as first-class source files. repoctx's AST-backed code map already knows kind: source/scripts vs kind: controller/authentication. Absorbing impact-map = throwing away scanner.py + extractors.py and reusing code-map.js. Only ~250 LOC of scoring.py + text.py + validation.py is actually worth porting.

2. ๐ŸŽฏ Add kind/domain-aware penalties to scoring

After absorption, scoring should consume repoctx's kind field directly:

// pseudo
penalty if kind starts with 'source/docs' or path starts with 'documentation/'
penalty if extension in {.html, .css} unless query mentions ui/style/css
boost   if kind matches one of: controller, service, processor, dto

This single change would have moved stripe.processor.ts to #1 in Query 1.

3. ๐Ÿชž The "Apple โ†’ auth" gap is real

Neither tool knows that "Apple sign-in" is an auth concept. A small synonym/concept map would help both:

apple | google | oauth | sso          โ†’ boost auth domain
refund | chargeback | invoice         โ†’ boost payment domain
otp | 2fa | verify | mfa              โ†’ boost auth domain

This belongs in src/lib/risk-paths.js next to the shared keyword list โ€” same vocabulary, two uses.

4. ๐Ÿค pullpass + repoctx pr should merge, not compete

pullpass's Context Evidence block literally tells the user to run repoctx pr. After absorption that becomes:

repoctx review .  โ†’  runs map + impact + pr + pass, one verdict

pullpass is essentially the verdict layer wrapping repoctx pr. Putting them in one binary removes the "install Go just to get PASS/WARN/FAIL" friction.

5. โšก Speed gap is mostly Python startup + re-scan

The 5.2ร— gap isn't even Python vs Node โ€” it's repoctx having a cached .dev-context/index.json it can refresh incrementally vs impact-map cold-walking the FS every call. After absorption, repoctx impact inherits the cache for free.


๐Ÿชœ Refined absorption plan

Phase ordering

Phase Work ~LOC ~Days
1. Shared risk + fancy renderer ๐ŸŽจ src/lib/risk-paths.js, src/lib/render/fancy.js, retrofit doctor as demo ~400 1โ€“2
2. Absorb impact-map ๐Ÿ โ†’ ๐Ÿ“ฆ src/lib/impact.js (port scoring.py + text.py + validation.py), repoctx impact command, MCP tool, --diff-base validation, kind/domain penalties ~500 2โ€“3
3. Absorb pullpass local ๐Ÿน โ†’ ๐Ÿ“ฆ src/lib/pass-local.js, policy.js, codeowners.js, release-check.js, repoctx pass command ~800 3โ€“4
4. Absorb pullpass PR + composite ๐Ÿš€ src/lib/pass-pr.js (gh integration, 856 LOC ported), repoctx review composite, MCP review_pr tool ~900 3โ€“5

What to keep vs. drop from impact-map

Keep โœ… Drop โŒ
Weighted-token scoring formula (scoring.py:176-241) scanner.py โ€” repoctx's code-map.js is AST-backed
Dependency boost via import graph (scoring.py:272-305) extractors.py โ€” repoctx already extracts imports/routes/symbols
text.py stop-words, singularize, domain keywords report.py โ€” repoctx has its own renderer
Validation against git diff (validation.py, ~68 LOC) Standalone scanner, CLI, MCP entrypoint

What to keep from pullpass

Module New file Why keep
internal/local/evaluate.go src/lib/pass-local.js Local merge gate (secret/risk/validation/audit)
internal/githubpr/evaluate.go (856 LOC!) src/lib/pass-pr.js gh-driven review decision, mergeability, status checks, conversations
internal/codeowners/codeowners.go src/lib/codeowners.js Pattern matching + team membership
internal/policy/policy.go src/lib/policy.js standard / company / high-risk profiles
internal/rules/rules.go merge into src/lib/risk-paths.js Unified risk vocabulary
internal/release/check.go src/lib/release-check.js Release-discipline rules

CLI shape after absorption

repoctx impact . "add Stripe refunds to bookings"             # โ† was: impact-map
repoctx impact . "fix auth redirect" --diff-base HEAD --json

repoctx pass . --base origin/main                             # โ† was: pullpass local
repoctx pass . --policy high-risk --governance team
repoctx pass-pr 123 --comment                                 # โ† was: pullpass pr
repoctx pass-pr --governance solo

repoctx review . --base origin/main --request "add refunds"   # ๐Ÿš€ NEW: composite
# runs: code-map โ†’ impact โ†’ pr โ†’ pass, returns one verdict

Fancy output preview

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚  ๐Ÿ“‹  repoctx pass ยท merge readiness                         โ”‚
โ”‚  ๐Ÿ“‚  ~/projects/bashbop-api                                  โ”‚
โ”‚  ๐Ÿ”€  HEAD vs origin/main ยท 14 changed files ยท policy: high-risk
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

  โœ… Changed files          14 files scoped to api/, tests/
  โœ… Secret safety          no .env or credential paths touched
  โš ๏ธ  Risk review           5 sensitive paths changed
     โ””โ”€ ๐Ÿ’ณ src/payments/refund.ts
     โ””โ”€ ๐Ÿ” src/auth/session.ts
     โ””โ”€ ๐Ÿ—„๏ธ  prisma/schema.prisma
  โœ… Release check          CHANGELOG.md updated for 1.4.0
  โœ… Validation commands    npm run ci ยท npm test ยท npm run lint
  โœ… Dependency audit       package-lock.json present
  โŒ Review state           CODEOWNERS approval missing for prisma/
  โš ๏ธ  Policy profile        high-risk: record specialist sign-off

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚  ๐Ÿšฆ  VERDICT     โŒ  FAIL                 โ”‚
โ”‚  โ›”  blocked by  Review state             โ”‚
โ”‚  ๐Ÿ“  next step   request @data-team review โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

๐Ÿšง Phase 1 status

Phase 1 work was started and paused for this writeup. Task list:

# Task Status
1 Read existing risk-flag logic in pr-review.js โœ… done
2 Create src/lib/risk-paths.js shared policy module โณ pending
3 Create src/lib/render/fancy.js renderer โณ pending
4 Retrofit doctor command as fancy-renderer demo โณ pending
5 Add tests for risk-paths and fancy renderer โณ pending
6 Run full repoctx CI gate (npm run ci) โณ pending

Existing repoctx risk vocabulary (preserve in risk-paths.js)

Discovered in src/lib/pr-review.js:742-767:

request surface          โ† route | apiRoute | controller kinds
frontend/backend contract โ† apiClient kind
data model               โ† schema kind, prisma | migration paths
auth/security            โ† auth | session | jwt | permission | role | password | token
money flow               โ† payment | billing | checkout | webhook | stripe | refund
configuration            โ† config kind, package.json | lock | docker | configs | env
large file diff          โ† additions + deletions โ‰ฅ 300

This is more semantic than impact-map's RISK_KEYWORDS ("payments", "database") or pullpass's riskPathParts ("stripe", "prisma"). The shared module should keep repoctx's vocabulary and map the other tools' lists to these canonical flags.

Glyph mapping for the renderer

Flag Glyph
auth/security ๐Ÿ”
money flow ๐Ÿ’ณ
data model ๐Ÿ—„๏ธ
request surface ๐Ÿ“ก
frontend/backend contract ๐Ÿ”—
configuration โš™๏ธ
large file diff ๐Ÿ“ฆ
secret risk ๐Ÿšจ

Status glyphs: โœ… pass ยท โš ๏ธ warn ยท โŒ fail ยท ๐Ÿšฆ verdict ยท ๐ŸŽฏ primary ยท ๐Ÿฅ‡๐Ÿฅˆ๐Ÿฅ‰ ranks.


๐Ÿ”ญ Open follow-ups

  • Verify findings on a Next.js repo (snapabird-web) to make sure the documentation/* overweighting is a NestJS-specific artifact or a general problem.
  • Confirm CODEOWNERS team-membership scope โ€” needs a GitHub token with read:org. Document in the new repoctx pass-pr help.
  • Decide repoctx context deprecation path โ€” impact and context answer the same question with different vocabularies. Likely context becomes an alias for impact in the next major.
  • Confirm tool name pass-pr vs alternatives (pass --pr 123, pass remote, review). Current docs assume pass-pr but it's not shipped yet.

๐Ÿ“Ž Source files referenced

File Purpose
/Users/segzy/projects/impact-map/src/change_impact_analyzer/scoring.py Scoring formula to port
/Users/segzy/projects/impact-map/src/change_impact_analyzer/text.py Tokenizer + domain keywords
/Users/segzy/projects/impact-map/src/change_impact_analyzer/validation.py Diff-validation feature
/Users/segzy/projects/pullpass/internal/local/evaluate.go Local merge gate
/Users/segzy/projects/pullpass/internal/githubpr/evaluate.go gh-driven PR mode
/Users/segzy/projects/pullpass/internal/policy/policy.go Policy profiles
/Users/segzy/projects/pullpass/internal/rules/rules.go Risk path list
/Users/segzy/projects/pullpass/internal/codeowners/codeowners.go CODEOWNERS parser
/Users/segzy/projects/repoctx/src/lib/pr-review.js Existing risk-flag inference (preserve vocabulary)
/Users/segzy/projects/repoctx/src/lib/context-engine.js Existing task-context engine that impact will merge with
/Users/segzy/projects/repoctx/src/lib/code-map.js AST code map that replaces impact-map's scanner