Mã Nguồn Ngược Dòng Chương 87 / 209

Chương 87 — Ba giờ đêm

Lúc Minh bấm nút deploy, văn phòng không ai vỗ tay.

Không ai nói câu gì lớn. Không ai đứng sau lưng anh như trong mấy tấm ảnh startup hay chụp lúc ra mắt sản phẩm. Máy lạnh cũ vẫn rì rì trên đầu, cái bảng architecture dán trên tường hơi cong mép vì keo hai mặt rẻ tiền, ly cà phê đá của Khoa để quên trên bàn đã tan hết đá.

Minh ngồi thẳng lưng trước laptop. Màn hình terminal chạy từng dòng log màu trắng trên nền đen.

Running migration...
Applying schema_v12_debt_events...
Backfilling merchant debt snapshots...
Deploying sync-service v0.3.1...
Health check: OK

Hoàng đứng sau ghế Minh, tay khoanh trước ngực. Anh không chạm vào máy. Đã thống nhất như vậy: production deployment cho module đồng bộ mới do Minh thao tác, Hoàng review checklist cuối, Khoa và Trâm đứng sẵn phía chăm sóc khách hàng nếu có phản hồi.

Checklist chỉ có bảy dòng. Quá ngắn cho một thay đổi đụng tới database. Nhưng đó là checklist tốt nhất họ có sau hai tuần tranh luận, test staging và chạy mô phỏng với dữ liệu giả.

“Health check xanh,” Minh nói.

Giọng anh bình thường. Không hưng phấn. Không căng. Người đã nhìn code của mình chạy trong đầu trước khi nó chạy ngoài máy.

Hoàng nhìn dashboard. Ba ô chính hiện màu xanh: API latency, sync queue, error rate. Đường latency nhảy lên một chút, rồi hạ xuống. Error rate vẫn nằm sát đáy.

“Đợi hai mươi phút,” Hoàng nói.

Minh gật, không quay lại. “Em biết.”

Khoa đứng ở bàn ngoài, điện thoại trong tay, mắt nhìn màn hình dashboard chiếu trên TV nhỏ treo tường. Trâm ngồi cạnh, trước mặt là sổ tay ghi danh sách hai mươi khách hàng cũ cần gọi nếu có trục trặc. Cô mặc áo sơ mi trắng đã nhăn ở cổ tay, tóc buộc thấp, cây bút bi kẹp giữa hai ngón tay.

“Em có cần gọi trước cho chị Bảy không anh?” Trâm hỏi.

“Chưa,” Khoa nói. “Đừng làm người ta lo trước khi có chuyện. Cứ nhìn.”

Hoàng nghe câu đó và không phản đối. Mọi thứ trông ổn.

Năm phút đầu, dashboard xanh.

Mười phút, vẫn xanh.

Minh mở thêm tab logs, lọc theo merchant IDs đã nằm trong test group. “Event append bình thường. Adapter đọc được state cũ. Không có duplicate.”

Hoàng cúi xuống nhìn. Code mới không làm anh khó chịu lúc này. Trên màn hình, nó chỉ là các dòng log sạch, có timestamp, có correlation ID — thứ mà PHP monolith cũ của anh hiếm khi có đầy đủ.

“Latency hơi cao,” Hoàng nói.

“Do backfill đang chạy. Sau mười lăm phút sẽ xuống.”

Phút thứ mười tám, latency thật sự hạ.

Minh dựa lưng vào ghế lần đầu tiên trong chiều. Khoa thở ra qua mũi, cười một tiếng ngắn.

“Vậy là ổn hả?” Trâm hỏi, mắt vẫn nhìn dashboard.

“Chưa ai nói chữ đó,” Khoa đáp ngay. “Nhưng tạm thời chưa chết.”

Trâm cười nhỏ, rồi cúi ghi vào sổ: 17:42 deploy sync-service v0.3.1 — dashboard xanh.

Hoàng nhìn dòng chữ của cô. Chữ Trâm tròn, đều, rất khác chữ gạch nghiêng trong sổ của anh. Một dòng ghi chép đơn giản, không có trọng lượng lúc viết ra. Nhưng nếu có chuyện, nó sẽ thành mốc đầu tiên của timeline.

Anh không biết vì sao mình nghĩ đến chữ “nếu”. Dashboard vẫn xanh.

Đến phút thứ hai mươi ba, Minh nói: “Em để monitor chạy. Tối em ở lại thêm.”

“Ở lại hết,” Hoàng nói.

Minh quay lại nhìn anh.

“Deployment đụng migration,” Hoàng nói tiếp. “Không ai về trước mười giờ.”

Minh gật. “Được.”

Không khí nhẹ đi một nấc. Khoa mở điện thoại gọi một khách ở Gò Vấp hỏi thử app có chậm không. Người bên kia nói vẫn bình thường. Trâm gọi hai cuộc theo danh sách test, cả hai đều bảo vừa thêm khoản nợ mới, số hiện đúng. Phương Anh nhắn vào group: Có gì báo tôi. Tôi đang ở nhà đọc hợp đồng, điện thoại mở. Anh Tuấn gửi một sticker ngón tay cái rất cũ, kiểu người lớn mới dùng.

Hoàng ngồi xuống bàn mình. Anh mở dashboard riêng, kéo thêm tab database replication. Mọi con số không có gì bất thường.

Một phần trong anh muốn đứng dậy nói với Minh: tốt. Không phải chữ “tạm được”, không phải gật đầu, mà là nói thẳng. Tốt. Code này tốt. Quyết định này đúng.

Nhưng câu đó không ra khỏi miệng.

Anh chỉ nhìn màn hình, để đèn xanh phản lên mắt.

Đến mười giờ mười lăm, họ cho Trâm về.

“Em ở lại cũng không sửa được server đâu,” Khoa nói. “Mai còn đi học. Về ngủ.”

Trâm nhìn Hoàng, chờ xác nhận. Hoàng gật.

“Đi cẩn thận. Có cuộc gọi khách thì cứ bắt, nhưng nếu không gấp thì để sáng.”

“Dạ.”

Cô đeo balo, cầm sổ tay, ra cửa. Trước khi đi còn quay lại nhìn dashboard một lần. Nó vẫn xanh.

Mười một giờ, Khoa nằm dài trên ghế sofa nhỏ, điện thoại úp lên ngực. Minh vẫn code thêm script kiểm tra. Hoàng ngồi trước màn hình, mắt khô vì nhìn log quá lâu.

Mười một giờ bốn mươi, error rate nhích lên.

Không nhiều. Một vạch mảnh, rồi trở lại đáy.

Minh thấy trước Hoàng nửa giây. “Có một merchant sync failed. Retry pass rồi.”

“ID?”

“BT-017.”

Chị Ba Muối. Một tiệm ở Bình Thạnh. Hoàng nhớ vì chính Khoa đặt mã theo quận thời còn chưa có hệ thống đánh số tử tế.

“Gọi thử,” Hoàng nói.

Khoa bật dậy khỏi sofa, vuốt mặt, gọi. Chuông đổ lâu. Không ai bắt máy.

“Mười một giờ rồi,” Khoa nói. “Chắc ngủ.”

Minh mở log của merchant đó. “Network timeout. Retry xong. State consistent.”

Hoàng gật. Anh nhìn đường error rate. Nó lại nằm sát đáy.

Mười hai giờ hai mươi, thêm ba lỗi.

Lần này không tự hết nhanh. Sync queue nhích lên từ 12 lên 89, rồi 140. Latency bắt đầu rung.

Minh ngồi thẳng dậy. “Backfill job chưa dừng.”

“Không phải nó phải dừng từ nãy?” Hoàng hỏi.

“Phải.” Minh kéo terminal. “Cron bị trigger lại. Lạ.”

Khoa đi ra sau ghế họ. “Có nghiêm trọng không?”

“Chưa,” Minh nói.

Hoàng không thích chữ đó. Chưa.

Anh mở database console. Số bản ghi đang được migration cập nhật tăng nhanh hơn dự kiến. Adapter đọc state cũ và event mới cùng lúc. Một vài merchant có debt snapshot trống trong read model, nhưng event log vẫn còn.

“Dữ liệu có mất không?” Khoa hỏi.

Minh trả lời ngay: “Không mất. Event log còn.”

Hoàng nhìn read model. Với khách hàng, thứ họ thấy là read model. Event log còn hay không, chị Bảy không quan tâm. Chị mở app, thấy sổ nợ trống, với chị là mất.

“Disable backfill job,” Hoàng nói.

Minh gõ lệnh. “Đang disable.”

Queue tiếp tục tăng.

Một giờ kém mười, điện thoại Khoa reo.

Tên hiện trên màn hình: Trâm.

Khoa bắt máy ngay. “Alo?”

Giọng Trâm lọt ra ngoài vì văn phòng quá yên. “Anh Khoa, chị Bảy gọi em. Chị nói app hỏng rồi. Chị mở ra không thấy nợ của khách.”

Khoa nhìn Hoàng.

Hoàng kéo dashboard merchant search, gõ mã của chị Bảy: BT-001. Read model trống. Event log có dữ liệu. Snapshot mới nhất timestamp mười hai giờ bốn mươi ba, size zero.

Khoa nói vào điện thoại: “Em giữ máy với chị được không?”

“Dạ, chị đang la. Em nói em kiểm tra rồi gọi lại trong mười phút.”

“Đừng hứa mười phút,” Khoa nói ngay. “Nói mình đang xử lý, tiền nợ không mất. Nhớ câu đó trước. Tiền nợ không mất.”

Bên kia có tiếng Trâm hít vào. “Dạ.”

Rồi một giọng phụ nữ vang lên xa xa qua loa điện thoại, gắt và cao: “App của mấy đứa hỏng rồi! Sáng mai tao lấy gì tao bán? Khách người ta hỏi nợ tao nói sao?”

Chị Bảy.

Hoàng đã nghe giọng đó nhiều lần ngoài tiệm, giữa tiếng túi nylon sột soạt và mùi nước xả vải rẻ tiền. Giọng chị không có gì xa lạ. Chỉ là lần này nó đi qua điện thoại trong một văn phòng nửa đêm, trở thành tiếng chuông báo động thật hơn mọi dòng log đỏ.

Khoa nói nhanh: “Trâm, mở speaker cho chị nghe tao.”

Một tiếng lách cách.

“Chị Bảy, em Khoa đây.”

“Ủa Khoa hả? Cái app tụi bây sao vậy? Hồi chiều còn coi được, giờ trắng trơn. Mấy chục người nợ của chị đâu?”

“Dữ liệu không mất, chị. Bên em đang sửa phần hiển thị. Chị đừng ghi đè gì trong app lúc này. Nếu có khách mua chịu khuya thì chị ghi tạm ra giấy giúp em. Sáng em xuống tận nơi đối lại với chị.”

“Tiền người ta nợ tao mà tụi bây nói không mất là không mất hả?”

“Em chịu trách nhiệm,” Khoa nói. Không nhìn ai. “Nếu sáng mai thiếu một dòng, em ngồi ở tiệm chị dò lại từng người.”

Đầu dây bên kia im vài giây. Tiếng quạt, tiếng TV nhỏ, tiếng ai đó ho khan.

“Nhớ đó,” chị Bảy nói. “Tao tin mày nên mới xài.”

Câu đó làm Khoa nhắm mắt lại trong nửa nhịp.

“Dạ. Em nhớ.”

Cuộc gọi tắt.

Trâm vẫn trên máy của Khoa. “Anh ơi, em làm gì?”

“Em mở laptop được không?”

“Dạ được.”

“Anh gửi em danh sách khách đang báo lỗi. Gọi từng người theo script: dữ liệu không mất, bên mình đang sửa hiển thị, không nhập thêm dữ liệu mới nếu thấy sổ trống. Ai đang cần bán gấp thì ghi giấy tạm, sáng mình hỗ trợ đối soát. Không hứa giờ cụ thể. Không đổ lỗi mạng.”

“Dạ.”

“Và uống nước đi. Giọng em run.”

“Dạ.”

Khoa tắt máy, quay sang Hoàng. “Bao nhiêu?”

Hoàng nhìn dashboard. Error rate dựng lên như vết cắt. Sync failures: 47 merchants. Read model zeroed: 47.

“Bốn mươi bảy,” anh nói.

Văn phòng yên.

Minh đang gõ nhanh. “Event log còn. Snapshot job ghi sai state vào read model. Em có thể viết script rebuild từ event log. Chưa cần rollback toàn bộ.”

“Bao lâu?” Hoàng hỏi.

“Hai mươi phút nếu chỉ rebuild 47 merchant. Ba mươi nếu thêm validate.”

Hoàng nhìn đồng hồ. 00:58.

“Rủi ro?”

“Không lớn. Event log append-only, dữ liệu gốc còn.”

“Rủi ro là gì?”

Minh ngừng nửa giây. “Nếu event ordering có vấn đề trong nhóm multi-device, rebuild ra state sai thứ tự. Nhưng em có idempotency key, có timestamp, có sequence.”

“Đã test production data chưa?”

“Chưa thể test production data trước khi production có lỗi.”

Câu đó đúng. Và vô dụng.

Hoàng mở tab backup. Last full backup: 23:00. Trước lỗi. Nếu rollback về backup, mất dữ liệu nhập sau 23:00, nhưng có thể lấy event log mới để đối soát. Thời gian downtime: hai đến ba tiếng. An toàn hơn. Chậm hơn. Rewrite của Minh bị revert khỏi production.

Minh nhìn anh. “Anh đang nghĩ rollback.”

Hoàng không trả lời.

“Không cần rollback,” Minh nói. “Lỗi nằm ở snapshot job. Tắt job, rebuild read model. Code sync service không sai lõi.”

“Read model của 47 khách đang trắng.”

“Vì snapshot sai. Em fix được.”

Khoa nhìn qua lại giữa hai người. “Nói tiếng người cho tao.”

Hoàng nói: “Rollback là quay về bản cũ lúc 11 giờ. App chạy lại theo hệ thống cũ. An toàn hơn, nhưng mất thời gian và phải đối soát dữ liệu nhập sau đó.”

Minh chen vào: “Hotfix là sửa đúng chỗ hỏng, giữ hệ thống mới. Nhanh hơn nếu làm đúng.”

“Nếu làm sai?” Khoa hỏi.

Minh nhìn Khoa. “Có thể làm sai state của vài khách phức tạp hơn.”

“Vài là bao nhiêu?”

“Em chưa biết.”

Khoa chửi một tiếng rất nhỏ.

Hoàng nhìn đồng hồ. 01:02. Họ có mười phút trước khi số cuộc gọi tăng. Chủ tiệm ngủ sớm, nhưng app của họ không chỉ dùng ban ngày. Có người ghi nợ cuối ngày, có người kiểm sổ trước khi đóng cửa, có người dậy sớm bán hàng lúc bốn giờ. Nếu đến bốn giờ app vẫn lỗi, chị Bảy không phải người duy nhất gọi.

Anh mở Hệ thống theo phản xạ.

Không có nhiệm vụ mới. Không có gợi ý. Chỉ số Độ bền tổ chức Lv.2 nằm im. Ở góc cảnh báo, dòng cũ vẫn nhạt nhòa:

KÊNH THÔNG TIN NGOÀI TỔ CHỨC — CẤP ĐỘ: CAO

Không liên quan. Hoặc quá liên quan.

Hoàng tắt nó ngay.

Minh nói: “Anh, để em hotfix.”

Hoàng quay sang anh. “Kế hoạch rollback.”

Minh đứng bật dậy. Ghế trượt ra sau, bánh xe đụng chân bàn.

“Anh nghe em nói không? Event log còn. Rollback toàn bộ là đập bỏ phần đang chạy đúng vì một job sai.”

“Khách đang thấy mất dữ liệu.”

“Và em có thể đưa dữ liệu về.”

“Bằng script chưa test production.”

“Rollback cũng không tự nhiên sạch. Anh sẽ phải merge data sau 23:00. Anh đang chọn một rủi ro khác, không phải chọn không rủi ro.”

Hoàng biết. Anh biết rất rõ. Rollback không phải nút thần kỳ. Nó là kéo hệ thống về trạng thái cũ rồi trả nợ bằng tay. Nhưng đó là loại nợ anh hiểu. PHP monolith cũ, backup cũ, bảng cũ, script cũ — anh có thể đi từng dòng. Hotfix của Minh nằm trên event log mới, adapter mới, snapshot mới. Anh review được logic, nhưng khi sản xuất đổ máu, anh không muốn học thêm logic.

Khoa nói: “Hai đứa quyết nhanh. Trâm đang gọi khách.”

Hoàng nhìn dashboard. 47. Con số không tăng trong một phút vừa rồi. Nhưng error rate vẫn đỏ.

Minh đặt hai tay lên bàn. “Cho em hai mươi phút.”

“Không.”

Một chữ. Khô.

Minh nhìn anh, mặt không đổi, chỉ quai hàm căng lên.

Hoàng nói: “Rollback về 23:00. Disable sync-service mới. Giữ event log để đối soát. Khoa, nhắn Trâm: mình đang phục hồi hệ thống cũ, dữ liệu không mất, sáng hỗ trợ từng khách bị ảnh hưởng. Gửi thông báo cho nhóm test trước, không public rộng.”

Khoa gật, mở điện thoại ngay.

Minh đứng nguyên. “Anh muốn em làm rollback hay anh tự làm?”

Câu hỏi bình thường. Giọng không bình thường.

Hoàng kéo laptop về phía mình. “Tao làm. Mày kiểm tra data sau rollback.”

Minh cười một tiếng không thành tiếng. “Tức là anh không tin em đụng production nữa.”

“Không phải lúc này.”

“Đúng. Không phải lúc nào cả.”

Hoàng không đáp. Anh nhập lệnh rollback. Tay anh không run, nhưng cổ tay cứng. Terminal hỏi xác nhận hai lần. Anh gõ YES bằng chữ hoa.

Rollback initiated...
Disabling sync-service v0.3.1...
Restoring schema_v11...
Restoring full backup 23:00...

Minh kéo ghế ngồi xuống lại. Anh không đeo headphone. Chỉ mở một tab khác, bắt đầu viết script export event log sau 23:00.

Khoa gọi liên tục. Trâm giữ tuyến khách hàng từ nhà. Một giờ mười lăm, thêm bốn khách nhắn vào fanpage. Một người ở Gò Vấp gửi ảnh màn hình trắng. Một tiệm quần áo ở Phú Nhuận nói khách cãi nợ ngay tại quầy. Khoa nhắn xin lỗi từng người, hứa sáng đối soát, tặng một tháng miễn phí cho nhóm bị ảnh hưởng nặng.

“Đền tháng miễn phí có cần hỏi Phương Anh không?” Khoa hỏi giữa hai cuộc gọi.

“Không,” Hoàng nói. “Cứ làm.”

“Mười hai tháng?”

“Một tháng cho 47 khách. Nếu ai mất giao dịch phải đối soát thủ công, thêm tháng nữa.”

Khoa gật. “Oke.”

Một giờ bốn mươi, restore xong schema cũ. API lên lại. Nhưng dữ liệu sau 23:00 cần merge. Minh đưa file export event log cho Hoàng, không nói thêm. Hoàng kiểm tra nhanh, viết script chuyển một phần event thành transaction cũ. Minh nhìn qua vai anh.

“Dòng đó sẽ duplicate nếu merchant nhập hai thiết bị,” Minh nói.

Hoàng dừng tay.

Minh chỉ vào đoạn code. “Ở đây. Anh đang dùng timestamp làm unique. Phải dùng idempotency key.”

Hoàng sửa.

“Còn chỗ này,” Minh nói. “Sequence null với event cũ.”

Hoàng sửa tiếp.

Không ai nhắc lại chữ hotfix.

Hai giờ bảy phút, dashboard xanh.

Không phải xanh đẹp như chiều. Xanh sau khi bị lau máu. Error rate về đáy. Sync queue rỗng. API latency ổn. Read model của 47 khách đã có dữ liệu trở lại trong hệ thống cũ. Một vài giao dịch sau 23:00 được đánh dấu cần đối soát thủ công.

Khoa gọi Trâm. “Xong phần lớn rồi. Em nhắn chị Bảy mở lại thử.”

Ba phút sau, điện thoại Khoa rung. Tin nhắn từ Trâm: Chị Bảy thấy lại sổ rồi. Chị nói sáng xuống quán.

Khoa đọc to. Không ai cười.

Hoàng ngả lưng vào ghế. Đến lúc ấy anh mới nhận ra sau gáy mình ướt mồ hôi, dù máy lạnh vẫn chạy. Mùi cà phê nguội, mùi dây điện nóng, mùi người thức khuya trộn vào văn phòng nhỏ.

Phương Anh gọi lúc 2:18.

Hoàng bắt máy.

“Ổn chưa?” cô hỏi.

“Ổn tạm. Rollback về bản cũ. 47 khách bị ảnh hưởng trong khoảng ba tiếng. Không mất dữ liệu gốc, nhưng có vài giao dịch cần đối soát sáng mai.”

“Ghi timeline lại chưa?”

Hoàng nhìn sổ của Trâm để trên bàn, dòng 17:42 vẫn nằm đó. Sau nó là những dòng Khoa viết vội bằng chữ xấu: 00:47 first report, 00:58 47 merchants affected, 01:05 rollback initiated, 02:07 service stable.

“Có.”

“Đừng sửa gì thêm đêm nay nếu không cần,” Phương Anh nói. “Mai làm bản tường trình.”

“Ừ.”

Cô ngừng một chút. “Minh sao?”

Hoàng nhìn sang. Minh đang ngồi trước laptop, màn hình sáng lên khuôn mặt nhợt. Anh xem lại branch rewrite-v2, không gõ.

“Đang ở đây.”

“Anh sao?”

Hoàng không trả lời ngay.

Phương Anh nói: “Ngủ được thì ngủ. Không ngủ được thì ít nhất đừng quyết thêm gì.”

Cuộc gọi tắt.

Văn phòng còn ba người. Trâm ở nhà, vẫn nhắn báo tình hình. Khoa ngồi bệt xuống sàn, lưng tựa sofa, cầm điện thoại bằng hai tay. Minh đứng dậy đi rửa mặt ở toilet cuối hành lang. Tiếng nước chảy lâu hơn bình thường.

Hoàng mở dashboard lần nữa. Xanh. Anh không tin màu xanh đó như hồi chiều nữa. Nó giống tờ giấy đã bị vò rồi vuốt phẳng — vẫn đọc được chữ, nhưng nếp gấp còn nguyên.

Minh quay lại, tóc mái ướt, tay áo xắn lên. Anh lấy balo dưới bàn, bỏ sạc laptop vào.

“Mai em đến mấy giờ?” Khoa hỏi, giọng cẩn thận.

Minh nhìn đồng hồ. 02:31.

“Chưa biết.”

Khoa nhìn Hoàng. Hoàng không nói.

Minh kéo khóa balo. Âm thanh kim loại rít qua phòng.

Hoàng đứng dậy. “Minh.”

Minh dừng tay, không quay hẳn lại. “Dạ?”

“Code của mày không bị xoá. Branch vẫn còn. Mai mình xem lại.”

Minh quay lại lần này. Mắt anh đỏ vì thức, không vì khóc. Anh nhìn Hoàng như nhìn một bug khó chịu đã tái hiện nhiều lần nhưng chưa ai chịu đọc log.

“Anh nghĩ vấn đề là code của em bị xoá hay không à?”

Hoàng không trả lời.

Minh đặt balo xuống bàn. Không mạnh. Chính vì không mạnh nên tiếng đặt nghe rõ.

“Nếu anh tin em từ đầu,” Minh nói, từng chữ đều, “em fix trong hai mươi phút. Bây giờ anh mất ba tiếng rollback.”

Khoa ngồi dưới sàn ngẩng lên. Văn phòng yên đến mức nghe được máy lạnh nhả nước trong ống.

Hoàng nhìn Minh. Câu đó đúng về kỹ thuật. Ít nhất một phần lớn là đúng. Minh đã nhìn ra snapshot job, đã có event log, đã biết rebuild. Nếu cho anh hai mươi phút, có thể hệ thống đã phục hồi nhanh hơn. Có thể chỉ mất ba mươi phút. Có thể không cần kéo PHP cũ trở lại.

Nhưng câu đó cũng sai theo cách không thể chứng minh bằng log.

Tin em từ đầu. Từ đầu nào? Từ chiều deploy? Từ cuộc họp stack? Từ email với Raj mà Hoàng chưa hỏi? Từ lần đứng hành lang ở Singapore? Hay từ ngày Minh bước vào quán cà phê gần Bách Khoa và nói hệ thống này không sống nổi thêm sáu tháng?

Hoàng có thể nói: đây không phải chuyện tin. Đây là production. Đây là dữ liệu khách hàng. Đây là rollback policy. Đây là trách nhiệm CEO.

Nhưng policy chưa có. Quy trình chưa có. Chỉ có Hoàng ngồi đó, nhìn dashboard đỏ, và chọn thứ anh hiểu hơn.

“Đêm nay dừng ở đây,” Hoàng nói.

Minh nhìn anh thêm một nhịp. Rồi gật.

“Dạ.”

Một chữ đó lịch sự hơn mọi câu mắng.

Minh đeo balo lên vai. Anh đi quanh bàn nhặt sổ tay, dây sạc, áo khoác mỏng. Không vội. Không ném đồ. Không đóng sầm laptop. Mỗi động tác đều gọn, đều, kiệt sức.

Khoa đứng lên. “Để tao chở mày về?”

“Không cần. Em gọi xe.”

“Giờ này—”

“Không cần,” Minh lặp lại.

Khoa im. Lần này anh không ép.

Hai giờ năm mươi tám, Minh đứng ở cửa. Anh nhìn lại văn phòng một lần — dashboard xanh trên TV, ghế sofa lộn xộn, ly cà phê nguội, sổ tay của Trâm mở giữa bàn, Khoa đứng cạnh tủ lạnh, Hoàng đứng gần bàn Minh.

“Mai em nhắn,” Minh nói.

Không nói nhắn lúc nào. Không nói sẽ đến.

Cửa mở ra, hành lang tối hiện lên sau lưng anh. Đèn huỳnh quang ngoài đó nhấp nháy hai cái rồi ổn định. Minh bước ra. Cửa đóng lại rất nhẹ.

Ba giờ đêm.

Khoa thở ra, đưa hai tay vuốt mặt.

“Mai tính,” anh nói, không rõ nói với Hoàng hay với chính mình. “Tao về trước. Sáng sáu giờ tao xuống chị Bảy.”

“Ừ.”

“Ngủ chút đi.”

Hoàng gật, dù biết mình sẽ không ngủ ngay.

Khoa lấy chìa khóa, đi sau Minh vài phút. Văn phòng còn một mình Hoàng. Máy lạnh vẫn chạy. Dashboard vẫn xanh. Dưới sàn, chỗ Minh vừa đứng có một vệt nước nhỏ từ tóc anh rơi xuống sau khi rửa mặt, loang trên gạch men rồi mỏng dần.

Hoàng đứng nhìn vệt nước đó. Anh nghĩ đến câu Minh vừa nói, và thấy nó không giống một câu nói. Nó giống dầu đổ ra sàn — không lớn, không ồn, nhưng dính vào đế giày. Đi đâu cũng kéo theo.

Nếu anh tin em từ đầu.

Hoàng tắt TV dashboard. Màu xanh biến mất khỏi tường. Văn phòng tối hơn, chỉ còn ánh đèn laptop của anh.

Anh không mở Hệ thống.

Đêm nay, không cần thêm một chỉ số nào để biết có thứ đã nứt.