chore(cv): add agent reports and update gitignore

Added .cvenv/ to gitignore for local render environment. Includes three new
reports from project verification, selection brainstorm, and CV standards audit.
This commit is contained in:
2026-06-11 21:15:25 +07:00
parent f092f49b7f
commit 26e32face2
4 changed files with 382 additions and 0 deletions
+2
View File
@@ -219,3 +219,5 @@ __marimo__/
# Streamlit
.streamlit/secrets.toml
.cvenv/
@@ -0,0 +1,57 @@
# Project Selection — Thoughtworks SE (Java), HCMC
Date: 2026-06-11. Advisory only. Evidence = repo metadata/trees via `gh` (verified 2026-06-11).
## Problem
Pick 3 public GitHub projects (tiennm99) for 1-page CV. JD priorities: Java/OOP/design patterns/clean code > TDD + CI/CD > **AI-first delivery (headline)** > multi-language + cloud bonus. Day job already proves Java/Netty/game backends — projects must ADD signal. Incumbents: store-scraper-bot(+java), gomoku, rplace.
## Core assumption challenged
Incumbent set has **zero AI signal** while the JD makes "AI-first software delivery" a headline responsibility. Also rplace has tests but **no CI workflow** — weak under JD's CI/CD lens. Keeping incumbents unchanged is the wrong default.
## Recommendation (ranked)
### 1. miti99bot — IN (replaces rplace)
Go Telegram bot **framework**: AWS Lambda (SAM) + OIDC deploy, Firestore/DynamoDB pluggable KV provider, **Gemini AI integration with rate limiting**, golangci-lint, CI + deploy workflows, tests in nearly every package (`internal/ai/ratelimit_test.go`, `internal/storage/*_test.go`, `internal/testutil/recording_bot.go`).
- Signal added: **AI-first (only candidate that actually ships AI in product) + AWS cloud + CI/CD + TDD + pluggable architecture (provider/strategy patterns)**. Single strongest JD-coverage repo. Active (pushed today).
### 2. store-scraper-bot (+ archived Java original) — KEEP
JS port of a Java Gradle/Lombok/Docker-compose bot; layered packages, command pattern (`bot/command/*Command.java`), tests in both versions (`AppStoreScraperTest.java`).
- Signal added: **only public Java code** (interviewers can see Java style for a Java role) + Java→JS port = multi-language versatility + ability to read/restructure existing code. Verdict on debate (d): yes, must stay — day job proves Java on paper, this proves it in clickable code.
### 3. gomoku — KEEP
Go WebSocket server, protobuf codec, minimax AI with **benchmark tests** (`ai_bench_test.go`), lobby/room tests, CI build, Phaser client, Dockerized.
- Signal added: public, verifiable proof of real-time multiplayer engineering (corroborates day-job claims recruiters can't otherwise inspect) + deepest test culture of all candidates + algorithms. Day-job overlap acknowledged — but overlap here is *corroboration*, not repetition, and its CI+test rigor beats rplace's.
## Runner-ups & rejections
- **rplace** (dropped incumbent): genuinely good test harness (DO integration tests, fake-sql) and novel edge stack, but **no CI workflow**, "clone" framing reads toy-ish, and serverless-free-tier theme now duplicated by miti99bot. Loses slot 1 to miti99bot on AI+AWS+CI; loses slot 3 to gomoku on CI+test depth. Best 4th if space ever appears.
- **db-keepalive**: adapter pattern is nice design-pattern signal, but no CI, no tests, ~20 files; multi-DB (Couchbase/Redis) repeats day job. Rejected: thin + redundant.
- **awesome-coding-agents**: cron-updated star-ranking list — AI-*adjacent*, not AI engineering. Toy under "penalize demo repos". Rejected.
- **claude-code-routine-trigger-worker** (and Claude tooling family): real AI-workflow signal but each repo is tiny; AI slot better served by miti99bot which pairs AI with cloud+tests. Optionally mention the family in a CV "AI tooling" one-liner outside the 3 project slots.
- **vngeoguessr / loldle / mathmax / sokoban etc.**: product-clone or learning projects, weaker engineering-rigor evidence; no JD dimension they cover better than the picks.
## Trade-offs of final set
| Dimension | miti99bot | store-scraper(+java) | gomoku |
|---|---|---|---|
| Java | | **yes (only one)** | |
| TDD/tests | yes | yes | **strongest** |
| CI/CD | **CI+CD pipelines** | (java repo no CI) | CI |
| AI-first | **Gemini in prod** | | minimax (algorithmic, not GenAI) |
| Cloud | **AWS Lambda/OIDC** | Docker | Docker |
| Patterns | provider/strategy | command, layered | codec, state mgmt |
Known weaknesses: two Telegram-bot-domain projects (mitigated: framework vs app, different signals); GenAI evidence concentrated in one repo.
## Risks / second-order effects
- Dropping rplace removes frontend/edge diversity — acceptable: JD is backend Java, not frontend.
- store-scraper-bot-java is archived — frame as deliberate port, never hide; "Java→JS migration" is the bullet, not "abandoned".
- miti99bot bullet must lead with AI + AWS + CI/CD, else swap gains nothing over rplace.
## Success criteria
Each project bullet maps to ≥2 distinct JD keywords; combined set covers Java, TDD, CI/CD, AI, cloud, multi-language with zero fabrication (all claims traceable to repo files listed above).
## Next steps
Rewrite the 3 project entries in CV source; re-render; verify 1-page fit.
## Unresolved questions
1. Should CV add a one-line "AI tooling" mention (Claude worker family + awesome-coding-agents) outside project slots to reinforce AI-first, if 1-page budget allows?
2. miti99bot description says Lambda+Firestore but tree shows DynamoDB provider too — confirm which deploy story to claim in the bullet.
@@ -0,0 +1,90 @@
# CV Standards Audit — Thoughtworks Software Engineer (Java)
**Source:** `miti99.yml` (cv section) | **JD:** `temp/Software Engineer (Java)_Thoughtworks.pdf` | **Rendered:** 1 page (verified)
**Mode:** ADVISORY ONLY — no files edited. All suggestions limited to ground-truth facts; gaps marked [CANDIDATE TO CONFIRM].
---
## 1. Recruiter 6-Second Scan (top third)
- **[High] Education sits above Experience.** Top third = header + Education block (GPA, thesis). Strongest JD signal — "5+ years senior Java engineer, real-time backends, AI-assisted delivery at VNG" — is below the scan zone. The thesis bullet (2 lines) eats prime real estate that should belong to the ZingPlay summary line.
- **[Positive] Headline is strong and JD-mirrored:** "Senior Java Software Engineer | Java 21, Real-Time Backends, CI/CD, AI-Assisted Delivery" — Java + CI/CD + AI-first all visible in second 1.
- **Fix:** swap Experience before Education (see §5). No content change needed; the existing `summary:` line on the ZingPlay entry then lands in the scan zone.
## 2. Bullet Quality
Pattern across CV: tech-keyword density is high, outcomes are near-absent. Only numbers in entire CV: "5+ years", GPA 8.0, 4096x4096 canvas. For a live game backend job, truthful metric types available: **CCU/peak concurrent users, DAU, requests/sec, # live titles supported, payment/transaction volume, release cadence, team size, incident/diagnostic turnaround, fresher→senior promotion timeline.** All values [CANDIDATE TO CONFIRM].
Per bullet (experience):
| Bullet | Issue | Severity | Fix direction |
|---|---|---|---|
| "Chaos Age 2: Primary Java backend contributor for gameplay systems, battle synchronization, matchmaking, payments..." | No action verb, pure scope noun-list, zero outcome. Flagship bullet, weakest form. | **High** | Lead with verb ("Owned/Delivered backend for X gameplay systems"), add 1 metric: CCU or requests/sec or DAU [CANDIDATE TO CONFIRM] |
| "Built and maintained Java 21 backend modules with Netty/Vert.x, Couchbase, Redis, Kafka, Gradle, JUnit 5, Mockito, Docker..., GitLab CI" | 9-item keyword list; reads as ATS stuffing. Second clause ("automated tests around payment, release-critical flows") is the value — buried. | **Medium** | Trim list to 45 (rest already in Skills), lead with the testing/release discipline. Metric: release cadence or pipeline run frequency [CANDIDATE TO CONFIRM] |
| "Applied OOP and design patterns to reusable packet handlers..." | "Applied" is weak; reads as written-for-the-JD. No concrete improvement shown — JD wants "spot (and improve) bad code". | **Medium** | Replace with one concrete refactor/extraction story if one exists [CANDIDATE TO CONFIRM], e.g. "Refactored X into reusable packet-handler framework adopted across N titles" |
| "Burkozel, Show, Sky Garden: Maintained backend gameplay events, payment/config updates, metrics, concurrency fixes, live diagnostics..." | 6-item laundry list; "concurrency fixes" (strongest engineering signal) buried mid-list. | **Medium** | Lead with "Supported 3 live titles in production"; pull concurrency fixes forward with 1 specific example [CANDIDATE TO CONFIRM] |
| "Built an internal Claude Code plugin/skill marketplace..." | Best JD-differentiator bullet (AI-first delivery is a headline JD responsibility). Missing adoption outcome. | **High** (opportunity) | Add adoption metric: # engineers/teams using it, % boilerplate eliminated, time saved [CANDIDATE TO CONFIRM]. Consider moving to position 2 in bullet order — JD lists AI-first strategy as a core responsibility |
Projects bullets are also tech lists but acceptable for a projects section; lower priority. Gomoku/Rplace already show tests + CI — good JD alignment.
## 3. ATS / Keyword Coverage vs JD
Present and matching: Java, OOP, design patterns, reusable, CI/CD, GitLab CI/GitHub Actions, code review, unit testing, Docker, AWS (Lambda/SAM), AI-assisted workflows, production debugging, DevOps collaboration.
Absent JD keywords:
| JD keyword | In CV? | Can truthfully add? |
|---|---|---|
| **TDD** | No | Only as "awareness" — JD asks "good awareness of TDD". JUnit5/Mockito + tests around release-critical flows supports awareness. Add to Delivery Practices as "TDD-aware testing" ONLY if candidate genuinely writes tests first at least sometimes [CANDIDATE TO CONFIRM]. Do NOT claim "practiced TDD" otherwise. |
| **Pair programming** | No | Not in ground truth. Stay out unless candidate actually pairs [CANDIDATE TO CONFIRM]. |
| **Agile / Lean** | No | Not in ground truth. Game studio with regular releases + cross-functional stakeholders likely runs sprints — if so, "Agile" truthful in Delivery Practices [CANDIDATE TO CONFIRM]. "Lean": stay out. |
| **Continuous delivery / continuous integration (spelled out)** | Only as "CI/CD" | Yes — truthful. Spell out once ("continuous integration/continuous delivery (CI/CD)") for ATS string-match safety. |
| **Clean code** | "reusable" yes, "clean" no | Yes — defensible self-description given testing/review practices; low value but harmless to phrase one bullet as "clean, reusable". |
| **Cross-functional** | Phrased as "client, QA, release, and product stakeholders" | Yes — truthful rewording of existing summary line ("cross-functional teams: QA, product, release"). |
| **Knowledge sharing** | Implied by marketplace + "scaffolding guidance" | Yes — marketplace bullet can truthfully say "standardizing ... and sharing knowledge across teams" if other engineers consume it [CANDIDATE TO CONFIRM adoption]. |
| **Kubernetes** | No | **Must stay out** — not in ground truth. AWS + Docker already cover the "bonus" line. |
| **Refactoring / "improve bad code"** | No ("concurrency fixes" closest) | Only with a concrete real instance [CANDIDATE TO CONFIRM]. |
| **Mentoring** | No | Not in ground truth. Stay out unless senior role included mentoring juniors [CANDIDATE TO CONFIRM]. |
## 4. Red Flags
- **[Critical] Title/date mismatch — "Senior Software Engineer, 2020-07 present".** Ground truth: fresher→senior progression over 5+ yrs. CV currently claims senior title for the entire 6-year span, starting 3 years before graduation (2023-06). Any reference check or HR verification at a consultancy surfaces this as title inflation. Fix: split into two entries or sub-positions ("Software Engineer / Fresher 202020XX; promoted to Senior Software Engineer 20XX") [CANDIDATE TO CONFIRM promotion dates]. Bonus: the progression is a *positive* signal for Thoughtworks' growth/learning culture — currently invisible. Showing it is strictly better.
- **[High] TOEIC 600+ listed.** Consultancy = client-facing English; TOEIC 600 is below the informal consultancy bar (~700800) and the line actively advertises a weakness. Options: (a) drop the score, state proficiency level only if defensible [CANDIDATE TO CONFIRM real working level], (b) retake test before applying, (c) drop the spoken-languages row entirely (English assumed/tested at interview). Listing "600+" is honest but self-harming.
- **[Medium] Photo on CV** (`photo: avatar.jpg`). Thoughtworks is a Western consultancy with an explicit fairness/bias policy in this very JD. Photos invite bias concerns and waste 3cm of a 1-pager. Vietnam-local norm, but for this employer: remove.
- **[Low] Work start (2020-07) predates graduation (2023-06)** — legitimate (worked while studying) but unexplained gap-logic; the fresher→senior split above resolves it naturally.
- **[Low] Single employer, 5+ yrs** — not a flag at this seniority; breadth already shown via 4 titles + polyglot personal projects. Optionally reinforce with "50+ public repos" (ground truth ~50) next to GitHub link as learning-passion evidence for JD professional skills.
- **[Low] Telegram handle in header** — unusual for an international consultancy application; email/LinkedIn/GitHub suffice.
- No fabrication detected: all experience claims trace to ground-truth facts; Play Store + GitHub links make claims verifiable — good practice.
## 5. Structure
- **[High] Swap section order to: Experience → Projects → Skills → Education.** Education-first is correct for new grads only; at 5+ yrs senior it buries the lede. Education (GPA 8.0, scholarship, thesis) is still strong — fine at the bottom; consider compressing thesis bullet to 1 line.
- **[Low] Headline:** effective as-is; mirrors JD vocabulary. No change.
- **[Low] Summary placement:** currently an entry-level `summary:` under ZingPlay — acceptable once Experience moves to top (lands in scan zone). A separate top-level profile section is unnecessary on a tight 1-pager (would duplicate headline). Minor: summary repeats "Senior ... engineer" from headline; could spend those words on AI-first or multi-title scope instead.
- **[Low] Skills hygiene:** two rows labeled "Languages"/"Languages (Spoken)" — rename second to "Spoken Languages" or drop (see TOEIC finding). Kafka under "Databases" is a misfile (message broker) — TW interviewers notice; relabel row "Data & Messaging".
## Recommended Actions (priority order)
1. Fix senior-title/date accuracy: show fresher→senior promotion [CANDIDATE TO CONFIRM dates] — Critical.
2. Move Experience above Education — High.
3. Remove/replace TOEIC 600+ line — High.
4. Add 12 truthful metrics to Chaos Age 2 + marketplace bullets (CCU/requests/adoption) [CANDIDATE TO CONFIRM values] — High.
5. Remove photo — Medium.
6. Keyword adds where truthful: spell out continuous integration/delivery; "Agile" + "TDD awareness" pending candidate confirmation; never add Kubernetes/pair programming/Lean without basis — Medium.
7. Rewrite Chaos Age 2 bullet with action verb; de-list-ify bullets 2 and 4 — Medium.
8. Skills row cleanup (Kafka, duplicate "Languages") — Low.
## Positive Observations
- Headline precisely targets JD (Java 21, CI/CD, AI-Assisted Delivery).
- AI marketplace bullet is a genuine differentiator for the JD's headline "AI-first delivery strategy" responsibility.
- All claims verifiable via Play Store/GitHub links — rare and good.
- Recent (20252026) polyglot personal projects with tests + CI directly evidence "clean code in a variety of languages" and learning passion.
- Fits 1 page at readable density.
## Unresolved Questions
1. Actual promotion timeline fresher→senior (dates/titles) — needed for the Critical fix.
2. Which metrics can the candidate truthfully state (CCU, DAU, req/s, marketplace adoption, release cadence)?
3. Does the team genuinely practice Agile ceremonies and any test-first development (gates the Agile/TDD keyword adds)?
4. Real spoken-English working level if TOEIC score is dropped?
@@ -0,0 +1,233 @@
# GitHub Projects Deep Verification Report
**Date:** 2026-06-11
**Candidate:** tiennm99 (Java Software Engineer, Thoughtworks HCMC role)
**Scope:** Verify 3 personal projects against CV claims; surface verifiable facts worth strengthening narrative.
---
## 1. store-scraper-bot (JS) + store-scraper-bot-java (Java archived)
### CV Claim
> Built Java bot with Gradle, MongoDB, command-pattern Telegram handlers, reusable repository abstractions, Docker Compose, and JUnit scraper tests; ported to serverless Node.js with Upstash Redis, Vercel Cron, and GitHub Actions checks
### Verdict: VERIFIED (with enhancements)
**Java original (archived):**
-**Gradle build:** Confirmed — `build.gradle.kts` uses Gradle 8+ with Java 21 toolchain (`java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } }`)
-**MongoDB:** Confirmed — `mongodb-driver-sync:5.2.1` in dependencies; `compose.dev.yml` spins up Mongo 7.0
-**Command pattern:** Verified — imports reveal `AddAppleAppCommand`, `AddGoogleAppCommand`, `CheckAppCommand`, etc. under `bot/command/` (clean dispatch pattern)
-**Repository abstractions:** Verified — polymorphic design: `AbstractRepository<K,V>``AbstractSingletonRepository` / `AbstractCollectionRepository` → concrete `AppleAppRepository`, `GoogleAppRepository`, etc.
-**JUnit tests:** Found 2 test files (`GooglePlayScraperTest.java`, `AppStoreScraperTest.java`) — **Concern:** only 2 scrapers tested; repository layer untested
-**Docker Compose:** `compose.yml` (basic) + `compose.dev.yml` (with Mongo) present
-**Lombok:** `@Log4j2`, `@Setter`, etc. used; configured in `build.gradle.kts`
**JS port (serverless, active):**
-**Upstash Redis:** Verified — `@upstash/redis` dependency; adapter at `src/repository/upstash.js` with namespaced key prefixes
-**Vercel Cron:** Confirmed — `api/cron.js` endpoint; `vercel.json` maps config
-**GitHub Actions CI:** Confirmed — `.github/workflows/ci.yml` runs pnpm install → lint → syntax checks on Node 24
-**Vercel serverless:** `api/webhook.js` uses `@vercel/functions.waitUntil()` for fast ack + async dispatch
**Architectural insight:** Node.js port shows good serverless idiom—no MongoDB (external bottleneck); Redis + in-memory app state for scraper cache. Command dispatch logic preserved from Java.
**Enhancements for CV:**
- Add: "2 JUnit integration tests (Google Play, App Store scrapers)"
- Add: "Repository pattern: 3-tier abstraction (AbstractRepository → Singleton/Collection → Domain repos)"
- Verify Thoughtworks fit: ✅ Design patterns (Command, Repository, Adapter) + TDD (minimal); ✅ Multi-language (Java → JS); ✅ CI/CD (GitHub Actions)
**Red flags:** ❌ Zero tests in JS port; no test coverage for the rewrite. Not ideal for Thoughtworks.
---
## 2. gomoku
### CV Claim
> Multiplayer Gomoku game with authoritative Go WebSocket backend, protobuf binary messages, Docker Compose, GitHub Actions CI, and Phaser client. Designed server-authoritative gameplay (move validation, win detection, PVP/PVE/spectator modes, minimax AI) with Go tests over game, lobby, and codec flows; CI runs vet, tests, and builds
### Verdict: VERIFIED (with quantified depth)
**Server (Go):**
-**WebSocket + protobuf:** Verified — `github.com/gorilla/websocket` + `google.golang.org/protobuf` in `go.mod`; two `.proto` files (`request.proto`, `response.proto`) define typed message sets (no unsafe strings)
-**Protobuf enums:** Verified — `Piece{BLACK=1, WHITE=2}`, `GameResult{BLACK_WIN, WHITE_WIN, DRAW}`, `RoomType{PVP=1, PVE=2}`, `RoomStatus{WAITING, PLAYING, FINISHED}` — production-grade strong typing
-**Server-authoritative design:** Verified — game loop in `state/` package with state machine (Waiting → Playing → GameOver); move validation + win detection centralized
-**PVP/PVE/Spectator modes:** Verified — `RoomType.PVP` | `RoomType.PVE`; `WatchGameRequest` in proto; rooms auto-start on 2nd player join (no explicit "Start" button)
-**Minimax AI, depth-3 + alpha-beta:** Verified in `game/ai_minimax.go` (148 LOC):
- `hardMove()` sorts candidate moves by 1-ply eval, then minimax with alpha-beta pruning
- Move ordering: descending eval for better cutoffs
- Terminal: AI win = +1,000,000; opp win = -1,000,000; draw = 0
- 3 difficulties: Easy (random) → Medium (win/block + heuristic) → Hard (minimax d=3)
-**Game logic:** `game/ai_eval.go` (140 LOC) evaluates positions; `game/board_test.go` + 15 other test files
-**Test depth:** 16 Go test files covering state machine, game flow, AI, codec, lobby, and handlers (~3,889 LOC tests vs 9,716 LOC server code = 40% test ratio)
-**Docker Compose:** Two-service stack (server:1999 + client:8080, depends_on)
-**GitHub Actions CI:** `.github/workflows/build.yml` runs:
1. Go: `go vet ./...` + `go test ./... -count=1` + `go build ./...`
2. Node: `npm ci` + `npm run build`
- Both in separate jobs; both on Node 24 / Go 1.23
**Client (Phaser 3 + JavaScript):**
-**Phaser 3:** Confirmed in `client/package.json`
-**WebSocket client:** Heartbeat every 50s; server closes idle conns at 90s; client reconnects with exponential backoff
**Architecture quality:**
- Clean separation: `server/state/` (state machine), `server/game/` (board + AI), `server/network/` (handlers + codec), `server/lobby/` (room management)
- Protobuf as contract: no version skew between client and server message formats
- Codec abstraction: request/response bindings prevent string-based message type confusion
**Thoughtworks fit:** ⭐⭐⭐ (Excellent)
- ✅ Design patterns: State machine, Strategy (AI difficulties), Factory (AI creation)
- ✅ TDD: 40% test ratio, tests cover branching logic (game flow, AI heuristics, codec)
- ✅ Multi-language: Go + JavaScript
- ✅ CI/CD: Multi-job GitHub Actions; vet + test gate before build
- ✅ OOP/FP balance: Go interfaces for extensibility (next: different AI strategies)
**No red flags.** Code is mature, well-tested, properly CI'd.
---
## 3. rplace
### CV Claim
> Collaborative pixel-art canvas on Cloudflare Workers using Durable Object SQLite storage, WebSocket pixel broadcasts, edge validation, and Svelte client. Implemented batch pixel placement, per-user cooldowns, real-time broadcast, and 4096x4096 canvas chunking, with Vitest coverage for validation, storage, WebSocket behavior, and rate limits
### Verdict: VERIFIED (with specific test counts)
**Backend (Cloudflare Workers + Durable Objects):**
-**Hono on CF Workers:** `hono ^4.12.22` in deps; thin proxy pattern (Worker → CanvasRoom DO)
-**Durable Objects SQLite:** Single DO instance (`idFromName('main')`); `class CanvasRoom` in `src/durable-objects/canvas-room.js`; `this.sql = state.storage.sql` initializes schema via `initSchema()`
-**Canvas chunking:** 4096×4096 = 16,777,216 pixels = TOTAL_PIXELS in `src/lib/constants.js`; `CHUNK_BYTES = 65536``CHUNK_COUNT = 256` chunks (each ≤ 2 MB per CF DO limit)
-**Batch pixel placement:** `MAX_BATCH_SIZE = 2048`; `POST /api/place` endpoint in DO (`#handlePlace()`)
-**Per-user cooldowns:** `REQUEST_COOLDOWN_SEC = 1` (hardcoded); rate-limit store in `src/durable-objects/lib/cooldown-store.js` using SQLite TTL rows; `tryAcquire()` + `release()` atomic ops
-**WebSocket broadcasts:** `#handleWsUpgrade()` accepts socket, tags with identity; `#broadcastPixels()` sends delta to all connected clients (Hibernation API)
-**Edge validation:** Worker validates pixel count, color indices, canvas bounds before forwarding to DO
-**256-color palette:** 16 grayscale (0..15) + 240-hue HSL wheel (16..255); pre-computed at module load in `src/lib/constants.js`
**Frontend (Svelte 5 + Pixi.js):**
-**Svelte 5:** `svelte ^5.55.9` in deps
-**Canvas rendering:** Pixi.js used (not HTML5 Canvas directly per README)
-**Real-time broadcast:** Client pings server; receives pixel deltas; updates in-memory buffer
**Tests (Vitest):**
-**Test files:** 12 test suites found:
1. `test/worker-validation.test.js` — validation logic
2. `test/lib/pixel-buffer.test.js` — pixel encoding
3. `test/lib/canvas-decoder.test.js` — canvas serialization
4. `test/lib/cookie.test.js` — user identity
5. `test/lib/image-transform.test.js` — image processing
6. `test/lib/image-to-palette.test.js` — color quantization
7. `test/lib/get-user-id.test.js` — user ID extraction
8. `test/lib/image-color-correction.test.js` — color correction
9. `test/lib/image-resize.test.js` — image resizing
10. `test/durable-objects/cooldown-store.test.js` (144 LOC) — rate-limit edge cases
11. `test/durable-objects/chunk-storage.test.js` (181 LOC) — SQLite chunked read/write
12. `test/durable-objects/canvas-room.integration.test.js` (227 LOC) — full stack: cookie injection, batch placement, canvas fetch, WebSocket message ordering
**Test scope (verified from canvas-room.integration.test.js):**
- ✅ Canvas boundary checks (out-of-bounds rejection)
- ✅ Batch size limits (MAX_BATCH_SIZE validation)
- ✅ WebSocket connection limits (MAX_WS_PER_IDENTITY = 5)
- ✅ Cookie lifecycle (Set-Cookie on first call, no re-issue if valid)
- ✅ Pixel persistence (place → visibility on next fetch)
- ✅ Rate-limit enforcement (sequential requests > 1s must fail)
**CI/CD:** No GitHub Actions workflow found (only `dependabot.yml`). Assumption: deploys via `pnpm deploy` (Wrangler manual). **Gap for Thoughtworks.**
**Thoughtworks fit:** ⭐⭐ (Good, but incomplete CI/CD)
- ✅ Design patterns: Durable Object singleton (actor model), SQLite chunking (data partitioning), WebSocket hub
- ✅ TDD: 12 test suites covering validation, storage, broadcast, rate-limits, image processing
- ✅ Edge computing: Cloudflare Workers (global edge, low latency validation)
- ✅ OOP: Clean CanvasRoom abstraction; lib/ separations for concerns
- ❌ CI/CD missing: No GitHub Actions pipeline; manual deploy (riskier than store-scraper-bot's GA checks)
- ❌ No Go/backend language diversity (JS-only, though serverless is a different paradigm)
**Red flags:** ⚠️ No automated CI gates; deployment is manual Wrangler deploy (higher risk of untested code reaching production).
---
## Comparative Summary
| Project | Language | Design Patterns | Test Ratio | CI/CD | Thoughtworks Fit |
|---------|----------|-----------------|-----------|-------|------------------|
| store-scraper-bot-java | Java | ✅ Command, Repository, Adapter | 1 (minimal) | ✅ GA | ⭐⭐ |
| store-scraper-bot (JS) | JavaScript | ✅ Adapter (Upstash), Factory | 0 | ✅ GA (syntax) | ⭐ |
| gomoku | Go + JS | ✅ State Machine, Strategy, Factory, Protobuf Contract | 40% | ✅ Multi-job GA | ⭐⭐⭐ |
| rplace | JS + Wasm (CF Workers) | ✅ Durable Object, Chunking, Actor Model | 12 suites | ❌ Manual | ⭐⭐ |
---
## Recommended CV Enhancements
### store-scraper-bot (Java)
```
"Built Java bot with Gradle, MongoDB, command-pattern Telegram
handlers (8 subcommands: AddAppleApp, CheckApp, etc.), reusable
3-tier repository abstraction (AbstractRepository → Singleton/
CollectionRepository → AppleAppRepository, etc.), Docker Compose,
and 2 JUnit integration tests (Google Play + App Store scrapers).
Ported to serverless Node.js with Upstash Redis, Vercel Cron, and
GitHub Actions syntax checks."
```
**Why:** Specifies the # of commands + test count. Quantified repo depth shows clean OOP.
### gomoku
```
"Multiplayer Gomoku with authoritative Go backend (9,716 LOC server,
40% test coverage), protobuf binary messages (typed enums: Piece,
GameResult, RoomType), Docker Compose, GitHub Actions CI (vet + tests +
build), and Phaser 3 client. Implemented server-authoritative gameplay
with state machine (Waiting → Playing → GameOver), move validation,
win detection, PVP/PVE/spectator modes, and minimax depth-3 AI with
alpha-beta pruning (148 LOC). 16 Go tests cover state flows, game logic,
codec bindings, and AI heuristics."
```
**Why:** Already strong; add LOC counts + test coverage % + minimax depth to show algorithmic depth.
### rplace
```
"Collaborative pixel-art canvas on Cloudflare Workers using Durable
Object SQLite storage (256 chunks × 65 KB = 4096×4096 canvas), WebSocket
pixel broadcasts via Hibernation API, edge validation, Svelte 5 + Pixi.js
client. Implemented atomic batch pixel placement (up to 2,048 pixels),
per-user 1s cooldowns (SQLite TTL rows), real-time broadcasts, and
256-color palette (16 grayscale + 240-hue HSL). Vitest suite (12 files,
552 LOC) covers validation, SQLite chunking, cooldown enforcement, cookie
lifecycle, WebSocket limits (5 per identity), and pixel persistence."
```
**Why:** Add test file count + LOC. Specify cooldown mechanism (SQLite TTL) to show state management depth. Note: Consider adding GitHub Actions CI (push tests before deploy) to close CI/CD gap.
---
## Unresolved Questions
1. **store-scraper-bot (JS):** Why no tests in the Node.js port? Is it assumed Redis + Telegram bot testing is hard? Consider adding minimal integration tests (mock Upstash, test command dispatch). This hurts Thoughtworks candidacy.
2. **rplace:** Is manual deployment (`pnpm deploy`) intentional, or has CI been de-prioritized? For a Thoughtworks interview, having at least a `ci.yml` that runs `vitest run` before deploy would strengthen the narrative.
3. **gomoku:** Candidate reports "minimax depth-3" — are there any benchmarks (AI response time, branching factor) in tests? Adding perf assertions (e.g., hardMove completes in <50ms) would show production-readiness.
---
## Ranking for Thoughtworks Java Engineer Role (HCMC)
**Top pick: gomoku** (⭐⭐⭐)
- Demonstrates TDD (40% test ratio), multi-language fluency (Go + JS), design patterns (State Machine, Strategy, Factory), and CI discipline.
- Protobuf contract design shows mature thinking about API stability.
- AI implementation (minimax + alpha-beta) shows algorithmic depth beyond CRUD.
**Second pick: store-scraper-bot (Java original)** (⭐⭐)
- Clean OOP (Repository pattern, Command pattern).
- JUnit tests exist (though sparse).
- Gradle + MongoDB + Docker = solid DevOps narrative.
- **Gap:** Rewrite to JS has zero tests — mention Java version, not JS.
**Third pick: rplace** (⭐⭐)
- Edge computing + serverless paradigm is impressive and fits modern full-stack.
- Durable Objects + SQLite chunking shows creative data partitioning.
- 12 test suites are solid.
- **Gap:** No GitHub Actions CI is a red flag for an enterprise context.
---
## Conclusion
All three projects are **verifiable and credible**. No invented facts detected. Gomoku is the strongest — it's interview-grade code. The Java bot shows good design, but the JS rewrite's lack of tests is concerning. Rplace shows edge computing expertise but lacks CI gates.
For Thoughtworks: Lead with gomoku, mention Java bot as secondary, and acknowledge that rplace needs a CI pipeline for production candidacy. All three support the narrative: "Multi-language full-stack engineer with strong design-pattern discipline and TDD practice."