Chương 63 — Quyền truy cập đầu tiên
Hoàng thức dậy lúc năm giờ rưỡi, sớm hơn thường lệ.
Không phải vì lo. Vì anh đã lên danh sách từ đêm qua: phân quyền repo, tạo branch riêng, quy tắc commit, template pull request, nhật ký thay đổi. Việc thuần kỹ thuật, kiểu một developer tốn hai mươi phút để config git permission. Nhưng Hoàng đã ngồi với danh sách đó suốt bốn mươi phút, thêm bớt, đổi thứ tự, xoá dòng này, thêm dòng kia — như thể anh đang soạn hiến pháp cho một nước có hai công dân.
Bên ngoài, hẻm Bình Thạnh còn tối. Tiếng xe bưu điện quét qua, tiếng chó hàng xóm sủa hai tiếng rồi im. Mẹ đã đi ca sáng từ năm giờ, để lại nồi cơm trên bếp và tờ giấy ghi nước mắm trong tủ lạnh. Ba chưa về ca đêm.
Hoàng ngồi vào bàn, mở laptop.
Terminal quen thuộc hiện lên, con trỏ nhấp nháy. Anh bắt đầu gõ lệnh tạo repository structure: private repo, access control by role, protected branches, mandatory review trước khi merge. Mỗi dòng lệnh rất ngắn. Nhưng mỗi dòng mang theo một câu hỏi anh đã cân nhắc đêm qua.
Quyền đọc: mở rộng cho Minh đủ phần code lõi — backend, sync engine, API layer, schema, config deployment.
Quyền ghi: giới hạn ở branch minh/sync-rewrite. Không push thẳng main. Không chạm production config.
Quyền review: mọi commit phải đi qua pull request. Hoàng là người duy nhất có quyền approve trước khi merge vào branch staging.
Anh dừng ở dòng cuối.
Người duy nhất.
Gõ xong, anh nhìn lại cấu trúc. Nó giống hệt quy trình anh từng thấy ở công ty cũ năm 2026 — nơi mà anh chỉ là một kỹ sư cấp trung trong đội hai mươi người, nơi review code là việc hằng ngày không ai suy nghĩ.
Ở đây, team có một người. Anh tự review code của mình suốt một năm rưỡi. Mỗi commit là quyết định của Hoàng, do Hoàng, vì Hoàng. Không ai phản biện, không ai hỏi tại sao viết vậy, không ai gõ comment bên cạnh dòng code anh chọn giải pháp nhanh thay vì giải pháp đúng.
Bây giờ anh đang dựng hàng rào cho người khác vào.
Hoàng tạo file CONTRIBUTING.md, viết quy tắc: mô tả commit rõ ràng, không commit secrets, mỗi PR cần mô tả vấn đề giải quyết và trade-off đã chọn. Rồi anh dừng lại, xoá phần trade-off đã chọn. Câu đó nghe như copy từ template công ty lớn, không giống thứ người ta viết khi mới chia quyền lần đầu.
Anh viết lại: Mỗi thay đổi lớn cần giải thích lý do. Nếu không chắc, hỏi trước khi viết.
Đơn giản. Đủ rõ.
Bảy giờ, anh gửi email cho Minh.
Anh Minh,
Em đã thiết lập repo và phân quyền. Anh sẽ nhận được invite trong vài phút. Quyền đọc mở cho phần lớn codebase. Quyền ghi giới hạn ở branch riêng. Mọi thay đổi lớn đi qua pull request.
File đính kèm: CONTRIBUTING.md (quy tắc commit), BRANCH_SETUP.md (hướng dẫn môi trường local).
Nếu anh cần thêm phần nào chưa được mở, nhắn em.
Hoàng đọc lại. Thêm một dòng cuối:
Buổi walkthrough chiều nay 14:00 qua Zoom, anh准备了 câu hỏi gì thì gửi trước.
Anh nhìn chữ ch准备了 mình vừa gõ nhầm — ngón tay trượt phím. Xoá, gõ lại: chuẩn bị.
Nhấn gửi.
Minh trả lời sau bảy phút. Không phải email — tin nhắn trong group chat kỹ thuật.
Nhận invite. Bắt đầu đọc.
Không cảm ơn. Không hỏi thêm. Không bình luận về quy tắc.
Hoàng nhìn hai câu đó, tự hỏi mình đang kỳ vọng gì. Một lời cảm ơn dài? Một nhận xét về cấu trúc phân quyền? Minh không phải người làm vậy. Anh ta nhận quyền truy cập như nhận cờ xuất phát: gật đầu rồi chạy.
Tin nhắn tiếp theo đến lúc chín giờ mười lăm, giữa tiết Toán của Hoàng. Điện thoại rung trong túi. Anh không nhìn. Nhưng ngón tay ngứa.
Giờ ra chơi, anh mở.
Minh đã gửi ba tin liên tiếp.
Tin đầu: Auth module — tốt hơn tôi nghĩ. Token rotation đúng cách. Ai thiết kế phần này?
Hoàng gõ: Em.
Trênlevel cho tuổi mười tám.
Hoàng không biết đó là khen hay mỉa mai. Với Minh, ranh giới đó rất mỏng.
Tin thứ hai: Deployment config — anh đang dùng single server, reverse proxy nginx, no load balancer. Đúng không?
Đúng.
Có khi nào server sập giữa đêm không?
Có. Một lần. Hồi blog kéo 300 đăng ký.
Anh fix thế nào?
Tăng resource tạm. Restart nginx. Không có failover.
Sống sót bằng tay.
Hoàng nhìn ba chữ đó. Sống sót bằng tay. Không phải câu buộc tội. Nhưng chính xác hơn bất kỳ lời buộc tội nào, vì nó mô tả đúng thứ đã xảy ra: anh ngồi một mình trước server lúc hai giờ sáng, restart bằng tay, vá query bằng tay, đẩy fix bằng tay, và sống sót.
Tin thứ ba dài hơn.
Sync engine — tôi vừa đọc hết phần queue. Đây là phần tôi muốn nói chuyện chiều nay.
Nhưng trước đó, một câu: anh viết phần này trong bao lâu?
Hoàng nhìn câu hỏi. Ngón tay dừng trên màn hình.
Anh nhớ chính xác. Sync engine phiên bản đầu tiên được viết trong hai ngày, giữa server sập và khách hỏi lỗi, chạy trên local, test bằng tay trên điện thoại cũ, đẩy lên production trong đêm thứ ba. Sau đó vá thêm conflict resolution trong một buổi sáng trước khi đi học. Retry logic thêm vào sau khi khách Bình Dương báo lỗi trùng.
Bốn lần vá. Bốn lần viết thêm. Không một lần rewrite.
Anh gõ: Hơn một năm, từng phần.
Có phần nào anh viết lại từ đầu bao giờ?
Không.
Vậy tôi muốn nói chuyện về điều đó chiều nay.
Hoàng úp điện thoại. Chuông vào lớp vang lên ở cuối hành lang.
Hai giờ chiều, Hoàng mở Zoom trong phòng học thư viện trống — chỗ duy nhất yên tĩnh đủ vào buổi chiều.
Minh xuất hiện trên màn hình. Cùng chiếc áo sơ mi xám, cùng ly cà phê đen. Nhưng hôm nay bàn anh có thêm ba tờ giấy in, bút đỏ gạch chì chằng chịt. Anh đã in code.
“Nếu em mở rộng share screen,” Minh nói ngay, “tôi sẽ đi nhanh.”
Hoàng share. Màn hình hiện editor, file sync_engine.js mở ra, bốn trăm dòng code nằm gọn trong khung nhìn.
Minh không nhìn màn hình. Anh nhìn tờ giấy in trước mặt.
“Tôi đánh dấu ba đoạn. Đoạn một, dòng 87 đến 120.”
Hoàng cuộn tới. Đó là phần retry queue — đoạn xử lý khi request timeout, quyết định gửi lại hay bỏ qua. Code gọn, logic rõ. Anh từng tự hào về đoạn này.
“Đoạn này thông minh,” Minh nói. “Anh phân loại được network error và logic error. Hầu hết app indie không làm được việc này.”
“Nhưng?”
“Nhưng idempotency key sinh bằng timestamp client. Nếu client gửi lại sau khi timeout, key mới được tạo mỗi lần. Server không biết request nào là gửi lại, request nào là thao tác mới.”
Hoàng đã biết điều đó. Minh đã chỉ ra trong audit. Nhưng nghe nói trực tiếp, nhìn code mình viết trên màn hình trong khi người khác chỉ từng dòng — cảm giác khác hơn đọc trên giấy.
“Em có thể sửa idempotency key thành hash của payload,” Hoàng nói.
“Được. Nhưng đó là vá.”
Hoàng không phản ứng trên mặt. Bên trong, một sợi dây nhỏ kéo căng.
“Đoạn hai, dòng 203 đến 250.”
Conflict resolution. Phần xử lý khi hai thiết bị cùng sửa một khách nợ. Hoàng chọn timestamp client làm truth source — cái nào mới hơn thắng.
“Em biết giả định giờ client lệch là rủi ro,” Hoàng nói trước khi Minh mở lời.
“Biết mà vẫn chọn?”
“Vì lúc đó cần chạy. Vector clock hoặc server-side versioning đều cần thời gian em không có.”
Minh gật. Không phải gật đồng tình. Gật kiểu tôi đã nghe lý do, giờ đến phần tôi muốn nói.
“Đoạn ba, dòng 340 đến hết.”
Phần cuối của sync engine — phần đẩy local queue lên server khi có mạng. Đây là đoạn code dài nhất, phức tạp nhất, và cũng là đoạn Hoàng viết cuối cùng trong chuỗi bốn lần vá.
“Đoạn này không tệ,” Minh nói. “Nhưng nó là bốn lớp vá chồng lên nhau. Mỗi lớp giải quyết một vấn đề riêng. Nhưng lớp dưới không được thiết kế để chịu lớp trên.”
Anh giơ tờ giấy in lên, chỉ vào những dòng bút đỏ.
“Lớp một: retry cơ bản. Lớp hai: phân loại lỗi. Lớp ba: conflict resolution. Lớp bốn: queue persistence. Bốn lớp đó hoạt động được vì anh viết tất cả — anh hiểu chúng giao tiếp với nhau thế nào. Nhưng nếu tôi vào sửa lớp hai, tôi phải hiểu lớp một và ba đang giả định gì. Và giả định đó không được ghi đâu cả.”
“Em có comment trong code.”
“Comment nói code làm gì. Không nói tại sao làm vậy.”
Hoàng nhìn màn hình. Bốn trăm dòng code nằm đó, quen thuộc như đường về nhà. Anh biết từng dòng, biết tại sao dòng này đặt trước dòng kia, biết comment nào anh viết lúc ba giờ sáng và comment nào viết lúc tỉnh táo. Nhưng Minh nói đúng: cái anh biết nằm trong đầu anh, không nằm trong code.
“Anh muốn nói gì?” Hoàng hỏi, giọng bằng hơn anh cảm thấy.
Minh đặt tờ giấy xuống.
“Tôi muốn rewrite module sync từ đầu.”
Im.
Không phải im lặng khó chịu. Im như khoảnh khắc người ta vừa đặt một vật nặng xuống bàn và chờ nó ổn trước khi ai lên tiếng.
“Rewrite,” Hoàng lặp lại.
“Không phải toàn bộ codebase. Chỉ sync engine. Bốn trăm dòng. Tôi viết lại trong branch riêng, hai tuần, trên sandbox. Khi xong, anh review, test, quyết định có merge hay không.”
“Hai tuần.”
“Đúng.”
“Trong lúc sodon đang beta ở Đà Nẵng.”
“Đúng.”
“Trong lúc em đang chuẩn bị tài liệu cho Singapore.”
“Đúng.”
“Và em cần sync engine hoạt động cho tám trăm người dùng đang dùng.”
“Cũng đúng. Nhưng sync engine hiện tại hoạt động vì anh đang vá nó mỗi tuần. Nếu anh bận — bận Cổng Việt, bận gọi vốn, bận thi, bận ngủ — ai vá?”
Câu đó chích đúng chỗ.
Hoàng nhìn màn hình Zoom. Minh ngồi thẳng, không dựa lưng. Mắt anh nhìn thẳng vào camera, không phải kiểu thách thức mà kiểu người đã nghĩ kỹ và không định rút.
“Em hiểu lý do của anh,” Hoàng nói chậm. “Nhưng rewrite bốn trăm dòng trong hai tuần — anh tính rủi ro thế nào?”
“Tính rồi. Rủi ro lớn nhất không phải rewrite sai. Rủi ro lớn nhất là rewrite xong, anh không merge vì quen với cái cũ.”
“Em sẽ không—”
“Anh sẽ.” Minh nói không do dự. “Không phải vì anh cố tình. Vì người viết code cũ là anh. Người biết nó chạy ra sao là anh. Khi nhìn code mới của người khác chạy đúng nhưng khác cách, phản ứng bản năng là thấy nó không an toàn. Tôi đã thấy điều đó ở ba công ty.”
Hoàng đặt tay lên bàn. Ngón tay gõ nhẹ hai cái — thói quen khi đang xử lý.
“Vậy đề xuất của anh là gì?”
“Rewrite trong sandbox. Anh giữ production. Tôi viết mới, test mới, document đầy đủ. Sau hai tuần, anh so sánh cũ và mới, quyết định dựa trên test case, không dựa trên cảm giác.”
“Test case ai viết?”
“Cả hai. Em viết test case cho behaviour hiện tại — đảm bảo code mới không phá thứ đang chạy. Tôi viết test case cho edge case mà code cũ không cover.”
Hoàng nhìn danh sách trên màn hình. Bốn trăm dòng. Một năm rưỡi vá. Bốn lớp chồng nhau.
Nếu anh nói không, Minh vẫn làm việc trong branch riêng, vẫn fix từng vết nứt, vẫn giữ sync engine cũ chạy. Nhưng mọi fix từ đây sẽ là lớp vá thứ năm, thứ sáu, chồng lên bốn lớp cũ. Và Minh biết điều đó — đó là lý do anh ta đòi rewrite thay vì patch.
Nếu anh nói có, anh mở cửa cho người ta đập một phần nhà mình xây, xây lại theo cách khác, và anh phải tin rằng cách khác tốt hơn — hoặc ít nhất đủ tốt để anh không hối hận.
“Em cần nói chuyện với Khoa và Phương Anh,” Hoàng nói.
“Lịch gì?”
“Ngày mai. Buổi trưa.”
Minh gật. “Gửi tôi agenda trước, tôi chuẩn bị.”
Anh tắt camera. Màn hình tối.
Hoàng ngồi trong thư viện trống, share screen vẫn mở, bốn trăm dòng code nằm trên màn hình như bản đồ của một thành phố anh xây một mình và vừa được ai đó đề xuất quy hoạch lại.
Anh không tắt editor. Anh ngồi nhìn.
Sáng hôm sau, Khoa đến quán nước quen trước Phương Anh mười phút.
Quán vắng hơn ngày thường — giữa tuần, học sinh còn trên lớp, chỉ vài người chạy xe ôm ngồi hút thuốc lá, uống trà đá. Khoa gọi ly nước sấu, ghé lưng vào ghế nhựa, kéo balô lên lòng lấy laptop ra rồi lại nhét vào. Hôm nay anh không cần máy.
Hoàng đến đúng giờ. Phương Anh sau hai phút, túi vải trên vai, sổ tay quen thuộc dưới nách.
Ba người ngồi quanh bàn nhựa tròn.
“Minh không tới?” Khoa hỏi.
“Anh ấy gửi đề xuất. Em trình bày.”
Hoàng mở vở bìa xanh, đặt giữa bàn. Trên trang đầu, anh đã vẽ sơ đồ: sync engine hiện tại, bốn lớp vá chồng nhau, và phiên bản rewrite Minh đề xuất.
Khoa nhìn sơ đồ. Nhìn thêm ba giây. Rồi hỏi câu mà Hoàng biết anh sẽ hỏi đầu tiên.
“Tao không hiểu sơ đồ này.”
“Tao biết.”
“Vậy nói bằng tiếng người.”
Hoàng gấp vở lại. “Nôm na: phần quan trọng nhất của app — phần đồng bộ sổ nợ khi mạng yếu — đang chạy trên code anh viết gối đầu lên nhau suốt hơn một năm. Mỗi lần có lỗi, anh vá thêm một lớp. Bốn lớp bây giờ. Minh muốn đập đi viết lại.”
Khoa uống nước sấu, chậm rãi đặt ly xuống. “Đập đi viết lại — bao lâu?”
“Hai tuần.”
“Trong lúc Đà Nẵng đang chạy.”
“Ừ.”
Khoa nhìn Phương Anh. Phương Anh mở sổ, đã ghi sẵn ba dòng từ trước.
“Câu hỏi của em không phải nên hay không nên,” Phương Anh nói. “Câu hỏi là: tiêu chí nào để quyết định?”
Khoa gật, như thể câu đó đúng ý anh.
Hoàng nói: “Tiêu chí của em là tốc độ và rủi ro. Rewrite mất hai tuần, trong lúc app đang chạy và đang có đối thủ.”
“Tiêu chí của Minh?” Phương Anh hỏi.
“Nền móng. Anh ấy nói bốn lớp vá không chịu được lớp thứ năm.”
“Vậy hai người đang tranh về hai thứ khác nhau.” Phương Anh gạch một đường dưới chữ tốc độ và nền móng. “Anh lo mất tốc độ vì đang bị đuổi. Minh lo nền móng vì đang chịu trọng lượng. Cả hai đúng. Nhưng nếu tiếp tục tranh trên mặt kỹ thuật, không ai thắng — chỉ kéo dài.”
Hoàng nhìn cô. “Vậy đưa về đâu?”
“Về người dùng.” Phương Anh đặt bút xuống. “Khách đang gặp lỗi gì? Lỗi nào do sync engine gây ra? Lỗi nào có thể biến thành mất dữ liệu thật?”
Khoa chen vào: “Khách Bình Dương tuần trước hỏi app chậm khi danh sách nợ dài. Hoàng sửa trong mười phút — thêm index. Nhưng có khách nào báo bị cộng nợ hai lần chưa?”
“Chưa,” Hoàng nói.
“Chưa, hay chưa ai phát hiện?” Khoa hỏi.
Câu đó khiến Hoàng dừng.
Anh đã thêm idempotency check sau khi đọc audit của Minh. Nhưng check đó là vá — lớp thứ năm. Nếu có khách bị nhân đôi nợ mà không nhận ra vì số nhỏ, anh sẽ không biết cho đến khi người ta cãi chủ tiệm.
“Chưa ai phát hiện,” anh nói thật.
Phương Anh viết thêm một dòng: Lỗi chưa xảy ra ≠ an toàn.
Rồi cô nói: “Vậy đề xuất của em: cho Minh rewrite trong sandbox. Không đụng production. Hai tuần. Sau hai tuần, kiểm tra: code mới giải quyết được những rủi ro nào code cũ không giải quyết được? Có phá hành vi hiện tại không? Anh quyết định merge hay không dựa trên test, không dựa trên ai nói hay hơn.”
Khoa nhìn Hoàng. “PA nói đúng đó. Mày đang lo mất kiểm soát hay lo app hỏng?”
Hoàng đặt tay lên bàn. “Cả hai.”
“Thì nói thẳng cả hai.” Khoa dựa lưng vào ghế. “Đừng gói chuyện quyền lực vào chuyện kỹ thuật. Mày giỏi kỹ thuật, nhưng chuyện ai quyết định kiến trúc không phải kỹ thuật. Nó là chuyện mày chịu được người khác nói nhà mày xây lệch hay không.”
Hoàng nhìn bạn.
Khoa không hiểu code. Khoa không biết idempotency key là gì, không biết vector clock khác timestamp thế nào. Nhưng Khoa hiểu giọng — và giọng Hoàng lúc tranh luận với Minh đã vượt khỏi chuyên môn từ lâu. Nó không còn là giải pháp nào tốt hơn. Nó trở thành ai có quyền quyết định thứ này sẽ được xây theo cách nào.
“Oke,” Hoàng nói. “Sandbox. Hai tuần. Minh viết, em review, test trước khi quyết định. Production vẫn là của em.”
Phương Anh gật. Khoa uống hết ly nước sấu.
“Nhưng có một điều,” Hoàng nói thêm. “Nếu rewrite xong và em thấy không merge được, Minh phải chấp nhận.”
“Anh ấy sẽ chấp nhận,” Phương Anh nói. “Vì anh ấy đã nói rõ: quyết định cuối là của anh. Anh ấy muốn quá trình, không muốn quyền phủ quyết.”
Hoàng nhìn cô. “Em đoán hay anh ấy nói?”
“Anh ấy nói. Trong email sáng nay. Em copy ra đây.” Phương Anh lật trang sổ, đọc: Tôi không đòi quyền quyết định cuối. Tôi đòi quyền được đề xuất nghiêm túc.
Khoa huýt sáo nhỏ. “Thằng này đi làm mà viết câu như đọc tiểu thuyết.”
“Thằng này nghiêm túc,” Hoàng nói.
“Vậy càng nên cho nó cơ hội nghiêm túc.” Khoa đứng dậy, vươn vai. “Mày lo cho đi. Tao đi gặp khách Bình Dương. Hỏi xem có ai bị cộng nợ hai lần không — khéo có mà chưa biết.”
Khoa xách balô, vẫy tay rồi đi. Tiếng dép kéo trên nền gạch quen thuộc.
Phương Anh đứng dậy chậm hơn. Cô thu sổ, nhìn Hoàng.
“Có chuyện em muốn nói riêng.”
“Hả?”
“Anh đang rất tốt trong việc chia quyền từng bước. Nhưng chia quyền không phải mở cửa từng lớp. Có lúc anh phải để người khác tự quyết định thứ anh chưa nghĩ tới.”
“Minh chưa cần quyền đó.”
“Chưa cần, hay anh chưa sẵn lòng?”
Hoàng không trả lời.
Phương Anh xách túi. “Nghĩ đi. Mai nói.”
Cô đi. Quán còn lại Hoàng và hai ly nước đã cạn.
Chiều hôm đó, Hoàng mở repo, tạo branch minh/sync-rewrite-v2, set quyền cho Minh push vào branch đó. Anh viết commit message đầu tiên trên branch mới:
Khởi tạo branch rewrite sync engine. Sẽ chứa phiên bản mới, không đụng production.
Rồi anh nhắn Minh:
Branch sẵn sàng. Anh bắt đầu khi nào cũng được.
Minh trả lời sau ba mươi giây:
Cảm ơn.
Hai chữ. Rồi anh offline.
Hoàng nhìn hai chữ đó trên màn hình. Cảm ơn. Ngắn đến mức gần như lịch sự qua loa. Nhưng với Minh, hai chữ đó nặng hơn một đoạn email. Anh ta không nói cảm ơn khi không có thật. Anh ta nói khi nhận được thứ anh ta xin.
Hoàng tưởng mình đã chia quyền.
Anh mở log repo, kiểm tra cấu trúc một lần cuối. Mọi thứ đúng: quyền đọc, quyền ghi, branch riêng, review required. Gọn gàng. An toàn. Chuyên nghiệp.
Rồi, lúc năm giờ chiều, điện thoại rung.
Thông báo từ Git: Minh đã bắt đầu push commit đầu tiên lên branch minh/sync-rewrite-v2.
Hoàng mở repo trên trình duyệt.
Commit đầu: Init sync engine v2 — design doc.
Anh nhấp vào file diff. Minh không commit code. Anh commit một file markdown: SYNC_REWRITE_DESIGN.md.
Hoàng đọc.
Văn bản dài hai trang, chia ba phần: vấn đề hiện tại, kiến trúc đề xuất, trade-off. Rõ ràng, gọn gàng, mỗi mục ngắn nhưng đủ. Giọng văn khô — kiểu kỹ sư viết cho kỹ sư, không có lời dẫn nhập, không có khẩu hiệu.
Hoàng đọc đến phần cuối, đoạn Minh liệt kê rủi ro của chính rewrite.
Rủi ro: trong thời gian rewrite, sync engine cũ tiếp tục chạy và tiếp tục tích luỹ nợ kỹ thuật. Nếu rewrite không merge được, nợ đó tăng thêm mà không giảm.
Dưới đó, Minh thêm một dòng không nằm trong cấu trúc tài liệu, như ghi chú cá nhân được quên xoá:
Kiến trúc hiện tại không sống nổi thêm sáu tháng nếu tiếp tục tăng trưởng theo tốc độ hiện tại.
Hoàng dừng cuộn.
Anh đọc lại câu đó.
Không sống nổi thêm sáu tháng.
Minh chưa nói câu đó trong cuộc gọi Zoom. Chưa nói trong tin nhắn. Chưa nói trong buổi họp trưa nay. Anh đợi đến khi có branch riêng, có file riêng, có không gian mình kiểm soát — rồi mới viết.
Không phải để công khai. Mà để ghi lại, bằng chữ, trong codebase mà Hoàng không thể xoá.
Hoàng ngồi nhìn màn hình.
Anh đã mở repo, chia branch, đặt quy tắc review, viết CONTRIBUTING.md, gửi invite. Anh đã làm tất cả việc đúng để chia quyền. Anh đã ngồi với Khoa và Phương Anh, nghe Phương Anh đưa về tiêu chí người dùng, nghe Khoa nói anh đang gói quyền lực vào kỹ thuật. Anh đã nhượng bộ — sandbox, hai tuần, production vẫn giữ.
Anh tưởng đó là chia quyền.
Nhưng chia quyền không phải trao chìa khoá.
Nó là mở cửa cho người khác bước vào, để người đó nhìn thấy căn nhà bạn xây — và nói với bạn rằng căn nhà đó nghiêng.
Rồi bạn vẫn phải để họ ở lại.
Hoàng đóng laptop.
Ngoài cửa sổ, hẻm lên đèn vàng. Tiếng xe máy, tiếng bà bán xôi, tiếng ai gọi con về ăn cơm. Bếp dưới nhà có mùi canh chua — mẹ hâm lại.
Anh đứng dậy, đi xuống bếp.
File SYNC_REWRITE_DESIGN.md vẫn nằm trong repo, trên branch mang tên người khác, trong ngôi nhà số mà anh vừa mở cửa.
Câu cuối của Minh nằm ở đó, chờ anh quay lại đọc lần nữa.
Không sống nổi thêm sáu tháng.
Hoàng rót nước vào ly. Uống. Vị nước lọc nhạt, lạnh tủ.
Lần đầu tiên, anh hiểu rằng chia quyền không bắt đầu bằng việc đưa task.
Nó bắt đầu bằng việc chịu được người khác nói nhà mình xây lệch — và không đập cửa.