SAFE Stabilization Refactor Report
Date: 2026-03-06
Scope: duplication inventory + runtime usage detection + safe consolidation plan
Mode: non-destructive (no runtime entrypoint removals)
Step 1 — Duplication Inventory
Summary
- TS/JS duplicate base pairs detected:
295(workspace-wide, excludingdist/,node_modules/,.next/,archive/) - Duplicate frontend portal tree overlap (
[locale]/(portal)vs[locale]/[country]/(portal)):70files with matching relative paths - High-risk mock/live duplication concentrated in gateway routes:
tenders,auctions,stakeholder-applications - High-risk service logic duplication:
svc-authvsidentity-infra(auth + stakeholder onboarding/reviewer flow)
Inventory Table (High-value clusters)
| Category | File A | File B | Used in runtime? | Import graph | Risk |
| --- | --- | --- | --- | --- | --- |
| TS/JS duplicate | services/svc-auth/src/security/jwt.ts | services/svc-auth/src/security/jwt.js | Yes (service runtime path is active) | services/svc-auth/src/server.ts imports ./security/jwt (extensionless) | High |
| TS/JS duplicate | services/svc-auth/src/security/password.ts | services/svc-auth/src/security/password.js | Yes | services/svc-auth/src/server.ts imports ./security/password | High |
| TS/JS duplicate | services/api/src/routes/tenders.ts | services/api/src/routes/tenders.js | Yes | services/api/src/server.ts mounts tendersRouter from ./routes/tenders | High |
| TS/JS duplicate | services/api/src/routes/auctions.ts | services/api/src/routes/auctions.js | Yes | services/api/src/server.ts mounts auctionsRouter | High |
| TS/JS duplicate | packages/ai-layer/src/index.ts | packages/ai-layer/src/index.js | Yes (used from web API routes) | apps/web/src/app/api/ai/ask/route.ts imports @kvary/ai-layer | High |
| TS/JS duplicate | packages/memory-layer/src/index.ts | packages/memory-layer/src/index.js | Yes | apps/web/src/app/api/ai/ask/route.ts imports @kvary/memory-layer | High |
| TS/JS duplicate | packages/core/index.ts | packages/core/index.js | Yes | referenced via @kvary/core and internal compat modules | Medium |
| Duplicate route tree | apps/web/src/app/[locale]/(portal)/tenders/page.tsx | apps/web/src/app/[locale]/[country]/(portal)/tenders/page.tsx | Yes (both routes active by URL design) | Next.js file-system router entrypoints | Medium |
| Duplicate route tree | apps/web/src/app/[locale]/(portal)/auctions/page.tsx | apps/web/src/app/[locale]/[country]/(portal)/auctions/page.tsx | Yes | Next.js file-system router entrypoints | Medium |
| Duplicate route tree | apps/web/src/app/[locale]/(portal)/vacancies/page.tsx | apps/web/src/app/[locale]/[country]/(portal)/vacancies/page.tsx | Yes | Next.js file-system router entrypoints | Medium |
| Duplicate route tree | apps/web/src/app/[locale]/(portal)/accommodations/page.tsx | apps/web/src/app/[locale]/[country]/(portal)/accommodations/page.tsx | Yes | Next.js file-system router entrypoints | Medium |
| Duplicate service logic | services/svc-auth/src/server.ts (/auth/signup, /auth/login, /auth/me) | packages/identity-infra/src/server.ts (/auth/signup, /auth/login, /auth/me) | Yes | gateway auth route proxies to AUTH_SERVICE_URL; identity-infra can run directly on separate port | High |
| Duplicate service logic | packages/identity-infra/src/server.ts reviewer actions | services/api/src/routes/stakeholder-applications.ts reviewer actions return 501 | Partially | gateway path currently blocks reviewer flow though backend logic exists in identity-infra | High |
| Mock vs live duplicate | services/api/src/routes/tenders.ts local legacy engine | services/svc-tenders/src/server.ts canonical tender APIs | Yes | gateway has proxy + local fallback + local legacy actions | High |
| Mock vs live duplicate | services/api/src/routes/auctions.ts local engine mutations | services/svc-tenders/src/server.ts auctions persistence APIs | Yes | gateway reads may proxy but writes are local engine | High |
| Mock vs live duplicate | services/api/src/routes/map.ts fixture-driven map/overview | no live map backend in mounted gateway routes | Yes (mock only) | gateway serves static/fixture map view | Medium |
Step 2 — Runtime Usage Detection
Runtime entrypoint detection basis
- Service entrypoints from package scripts:
services/api/src/server.tsservices/svc-auth/src/server.tsservices/svc-tenders/src/server.tsservices/svc-risk/src/server.tsservices/svc-kyc/src/server.tsservices/svc-carbon/src/server.tspackages/identity-infra/src/index.ts(viatsx)
- Frontend runtime:
- Next.js file-system routes in
apps/web/src/app/**
- Next.js file-system routes in
- Package export resolution:
- Some packages export
dist/*(safer) - Others export
src/index.tsdirectly (runtime ambiguity when.ts+.jscoexist in same folder)
- Some packages export
Classification Table
| Duplicate cluster | Classification | Reason |
| --- | --- | --- |
| services/*/src/*.ts + services/*/src/*.js pairs | ACTIVE (TS source), LEGACY (JS sibling) | dev scripts run TypeScript entrypoints; .js siblings are transitional artifacts and increase resolution ambiguity |
| packages/* that export dist/* but keep src/*.js siblings | LEGACY | runtime consumers should resolve dist; src .js files are not canonical output path |
| packages/ai-layer, packages/memory-layer, packages/identity-infra (export/run from src/*.ts) with src/*.js siblings | UNKNOWN/HIGH-RISK | active runtime from src, extensionless resolution may accidentally pick .js depending toolchain |
| [locale]/(portal) and [locale]/[country]/(portal) duplicate files | ACTIVE | both URL trees are active intentionally |
| Gateway local mock/fallback handlers for tenders/auctions | ACTIVE | currently reachable at runtime and used when upstream unavailable or for legacy mutation path |
| Gateway stakeholder reviewer 501 stubs vs identity-infra reviewer handlers | ACTIVE (stub), ACTIVE (implementation elsewhere) | contradictory active paths |
Rule applied: UNKNOWN duplicates are not deletion candidates.
Step 3 — Safe Consolidation Plan
Cluster A — TS/JS duplicate files
Current:
- source directories contain
.ts+.jssiblings
Plan:
- Keep TypeScript as canonical source.
- Keep JS siblings temporarily, but mark them as deprecated-generated artifacts.
- Move all generated JS ownership to
dist/only in each package/service. - Add CI check that blocks new
src/*.jssiblings for TypeScript modules (allowlist temporary exceptions).
Cluster B — Gateway mock/live duplication
Current:
- gateway mixes live proxy and local engine for tenders/auctions
Plan:
- Add explicit feature flags for local engines (default preserving current behavior).
- Emit source header (
x-kvary-source) when local engine/fallback is serving response. - In production profile, set local-engine flags
falseand use service proxy path only. - Keep compatibility for local developer demos.
Cluster C — Duplicate frontend route trees
Current:
- many duplicated pages between
[locale]/(portal)and[locale]/[country]/(portal)
Plan:
- Extract shared page content components in a neutral shared module tree.
- Keep route files as thin wrappers preserving URL structure.
- Consolidate one domain at a time (tenders -> auctions -> vacancies -> accommodations).
Cluster D — Auth/stakeholder service logic duplication
Current:
- auth and stakeholder flow split between
svc-authandidentity-infra
Plan:
- Decide canonical service owner for auth+stakeholder lifecycle.
- Route gateway reviewer actions to canonical backend (remove 501 stubs once validated).
- Keep non-canonical service behind compatibility boundary until data migration is complete.
Step 4 — Non-destructive Refactor Applied (This change set)
Applied only in gateway domain:
-
services/api/src/routes/auctions.ts- added
AUCTIONS_LOCAL_ENGINE_ENABLEDflag (defaulttrue) - local engine mutations now explicitly gated by this flag
- local responses are tagged with
x-kvary-source: gateway-local-engine - when disabled, route returns
503+ reasonCode without crashing
- added
-
services/api/src/routes/tenders.ts- added
LEGACY_TENDERS_LOCAL_ENGINE_ENABLEDflag (defaulttrue) - legacy local-engine endpoints gated behind this flag
- local fallback responses tagged with
x-kvary-source: gateway-legacy-local-engine - behavior remains unchanged by default
- added
No runtime entrypoint was removed.
Step 5 — Gateway Mock/Live Cleanup Status
- Done now (safe baseline): explicit flags + explicit response source headers.
- Next safe step:
- add environment profile docs:
- local/dev: local engines can stay
true - staging/prod: set local engines
false
- local/dev: local engines can stay
- add environment profile docs:
Step 6 — Frontend Route Consolidation Plan (No URL change)
Order:
- Tenders shared page extraction
- Auctions shared page extraction
- Vacancies shared page extraction
- Accommodations shared page extraction
Pattern:
- keep both route files as wrappers
- move shared logic/rendering into one shared component per domain
- validate rendering parity before deduping internals
Step 7 — Safety Checks
Completed:
- No service port changes
- No entrypoint removal
- No destructive file deletes
- No URL structure changes
Pending (environment limitation):
- TypeScript build/test execution was not run in this shell because
nodebinary is unavailable in the current execution environment.
Step 8 — Small Commit Plan
Suggested commit sequence:
chore(stabilization): add safe duplication inventory and runtime classification reportrefactor(api-gateway): gate local auctions engine behind feature flag and tag response sourcerefactor(api-gateway): gate legacy tender local engine behind feature flag and tag response sourcechore(stabilization): add src-js-duplicate CI guard (allowlist mode)refactor(web): extract shared tenders portal page logic for locale/country wrappers(separate PR)
Step 9 — Files that should NOT be touched yet
Do not modify in this stabilization batch:
services/svc-tenders/src/server.tsbusiness transitions (submit/approve/reject + KES flow)services/svc-auth/src/server.tsauth token/session/oidc flowpackages/core/**deterministic governance/ledger logicdocs/80_chain/**event contract docs (except explicit version updates when behavior changes)- DB migrations already applied in active environments
Final Architecture After This Consolidation Step
Current stabilized state:
- Gateway retains compatibility behavior.
- Local-engine behavior is now explicit and controllable by env flags.
- Local/mock response origin is observable via response header.
- No destructive removals were introduced.
- Duplication clusters are documented with clear ACTIVE/LEGACY/UNKNOWN classification for safe follow-up.