Sai sót ở đĩa master của Space Quest II
(lanceewing.github.io)- Trên Space Quest II 2.0D/2.0F 720KB Disk 1 của Sierra On-Line, mã nguồn trình thông dịch AGI không hiển thị trong danh sách tệp đã bị sót lại, và đây là trường hợp sai sót khi chuẩn bị đĩa master được sao chép nguyên sang đĩa thương mại
- Trong DOS FAT, xóa tệp không xóa dữ liệu mà chỉ đánh dấu các sector là chưa sử dụng, nên nếu dùng đĩa chưa format làm master thì dữ liệu cũ có thể theo toàn bộ các bản sao
- Trong vùng “free” 402.432 byte của Disk 1, thay vì giá trị đệm format 0xF6 lại còn sót mã nguồn C/assembly; kết quả trích xuất xác nhận 93 tệp, hơn 15.000 dòng, và khoảng 70% mã nguồn trình thông dịch AGI
- Thiết bị sao chép FormMaster có thể đã sao chép toàn bộ sector của đĩa theo từng byte thay vì theo tệp, khiến cả dữ liệu đã bị xóa không có trong danh sách tệp cũng có khả năng phát tán sang đĩa cho khách hàng và cửa hàng bán lẻ
- Sai sót xảy ra vào tháng 3/1988, cuối thời kỳ AGI, đã bị chôn vùi cho đến khi NewRisingSun có phát hiện được biết đến đầu tiên vào tháng 10/2016, và 36 năm sau trở thành tư liệu khảo cổ số để nhìn vào cách Sierra triển khai AGI
Dấu vết không lộ ra nếu chỉ xem danh sách tệp
- Đĩa mềm 720KB của Space Quest II phiên bản 2.0D và 2.0F bề ngoài không có gì đặc biệt, và danh sách tệp cũng trông như một đĩa game Sierra thông thường
- Trong thư mục của bản 2.0D không có tệp bổ sung khả nghi; các tệp dữ liệu chính như PICDIR, LOGDIR, VIEWDIR, SNDDIR, VOL.0, VOL.1 đều được tạo vào ngày 14/3/1988
- Các tệp
.OVLmang timestamp ngày 15/3/1988, còn mã trình thông dịch AGI có timestamp ngày 18/3/1988, để lại dấu vết cho thấy việc chuẩn bị Space Quest II 2.0D tại văn phòng Sierra đã diễn ra suốt một tuần - Dung lượng đã dùng của đĩa là 302.918 byte, còn dung lượng “free” hiển thị là 402.432 byte, tức phần trống còn lớn hơn cả phần đã dùng
Vùng chưa sử dụng lộ ra qua hex editor
- Trên DOS, các sector chưa sử dụng của đĩa mềm vừa format thường được lấp bằng giá trị đệm format 0xF6
- Disk 2 của Space Quest II 2.0D có các sector chưa sử dụng được lấp bằng 0xF6, nhưng Disk 1 thì không có lấy một sector chưa sử dụng nào được lấp bằng 0xF6
- Trên Disk 1, chuỗi byte 0xF6 liên tiếp dài nhất chỉ có 2 byte, và dù hơn nửa dung lượng được đánh dấu là “free”, dữ liệu cũ thực tế vẫn còn đó
- Trong vùng bị đánh dấu là chưa sử dụng có văn bản trông giống mã nguồn C, gợi ý rất mạnh rằng đĩa này từng được dùng cho mục đích khác trước khi trở thành master của Space Quest II Disk 1
- Trong hệ thống tệp DOS FAT, xóa tệp không loại bỏ dữ liệu thật sự mà chỉ đánh dấu sector có thể tái sử dụng, nên nếu tệp mới không ghi đè thì nội dung cũ vẫn còn nguyên
Mã nguồn trình thông dịch AGI còn sót lại
- Khi trích xuất văn bản ASCII từ vùng chưa sử dụng, người ta thấy các hàm C như
DisplayStatusLinevàStatusLineOn DisplayStatusLinelà đoạn mã hiển thị một dòng văn bản gồm điểm hiện tại và trạng thái bật/tắt âm thanh, liên hệ trực tiếp với thanh trạng thái màu trắng ở phía trên màn hình Space Quest II- Đây không phải mã dữ liệu game mà là mã nguồn thuộc chính trình thông dịch AGI của Sierra
- Trong các sector chưa sử dụng có một lượng lớn mã nguồn, và do mã được lưu trên các sector liên tiếp nên có thể trích xuất khá dễ rồi tách theo từng tệp
- Ở đầu mỗi tệp đều có chú thích ghi tên tệp nguồn, nên khá dễ tìm điểm phân tách; kết quả tách ra được tổng cộng 93 tệp
- 75 tệp mã nguồn C
- 16 tệp mã nguồn assembly
- 2 tệp DOS BAT
- Toàn bộ mã có hơn 15.000 dòng, và phần lớn các tệp ở trạng thái hoàn chỉnh
- Đĩa này chứa khoảng 70% mã nguồn trình thông dịch AGI của Sierra On-Line, bao gồm cả chú thích và lịch sử thay đổi
Lịch sử thay đổi và dấu vết của lập trình viên
- Phần chú thích header ở đầu một số tệp nguồn có mục Change History
- Header của
ANIMATE.Cchứa tên tệp nguồn, mô tả ngắn là “xử lý một chu kỳ hoạt ảnh trong adventure game”, cùng thông tin nhưcompile: MWC MWCdường như là trình biên dịch C của Mark Williams, vốn được dùng khá nhiều vào thời đó- Lịch sử thay đổi gồm ngày, giờ, chữ viết tắt của người sửa, và mô tả thay đổi
- Trong các chữ viết tắt đó, JAS là Jeff Stephenson, người chủ yếu làm mã trình thông dịch AGI, còn DCI là Chris Iden
- Robert Heitman cũng xuất hiện, nhưng trọng tâm chính của ông là các công cụ đồ họa như Picture Editor và View Editor, còn Jeff Stephenson và Chris Iden chủ yếu phụ trách mã trình thông dịch
Memory map của AGI.EXE và cách tính 70%
- Trên Space Quest II 2.0D 720KB Disk 1, ngoài 93 tệp nguồn còn có memory map của tệp thực thi AGI.EXE dài hơn 2.000 dòng
- Trong các game AGI phát hành, tên tệp thực thi của trình thông dịch chỉ là
AGIvà không thể chạy trực tiếp, nhưng trong quá trình phát triển người ta dùng trình thông dịch có thể thực thi trực tiếp với phần mở rộng.EXE - Một ai đó ở Sierra đã tạo memory map của AGI.EXE, tức trình thông dịch AGI, vào ngày 7/10/1987
- Mốc ngày này khớp với việc chú thích mới nhất trong lịch sử thay đổi của mã nguồn là vào tháng 9/1987
- Memory map cung cấp một danh sách khá đầy đủ các module và tệp nguồn cấu thành trình thông dịch AGI
- Có 98 tệp nguồn khác nhau xuất hiện trong memory map, và trong đó 71 tệp tồn tại đầy đủ trên đĩa SQ2
- Dựa trên tỷ lệ này, người ta tính ra rằng đĩa Space Quest II chứa khoảng 70% mã nguồn trình thông dịch AGI
- Một số module chỉ có tệp header C nên không được tính vào phép tính này
AGI như tài sản trí tuệ của Sierra
- Sierra On-Line đã trải qua giai đoạn khó khăn về kinh doanh vào khoảng thời điểm ra mắt King’s Quest năm 1984, và Ken Williams phải sa thải khoảng 100 nhân viên, giảm quy mô từ khoảng 130 người xuống còn khoảng 30 người
- Sau đó, thành công của hệ thống game phiêu lưu AGI và các trò chơi xây dựng trên nó đã góp phần xoay chuyển tình hình công ty
- Cuối năm 1984, King’s Quest lọt vào top 20 bảng xếp hạng doanh số phần mềm game máy tính và duy trì ở đó khoảng nửa năm cho đến trước khi King’s Quest II ra mắt
- Thỏa thuận với Tandy Radio Shack, qua đó bán các phiên bản game Tandy tại các cửa hàng Radio Shack, cũng góp phần hỗ trợ
- Từ năm 1985 đến 1988, các game AGI liên tục là bestseller, và trình thông dịch AGI là nguồn doanh thu chính cũng như tài sản trí tuệ cốt lõi của Sierra On-Line
- Việc 70% mã nguồn trình thông dịch AGI bị sao chép hàng loạt và gửi tới hàng chục nghìn hoặc hàng trăm nghìn khách hàng là một sai lầm lớn từ góc nhìn của Sierra
Hệ quả của việc quên format đĩa master
- Khi Sierra chuẩn bị phát hành game mới, họ tạo đĩa master production copy để dùng với thiết bị sao chép đĩa FormMaster
- FormMaster không chỉ sao chép tệp từ đĩa master mà sao chép toàn bộ mọi sector của đĩa theo từng byte, bất kể sector đó có được dùng hay không
- Với Space Quest II 2.0D và 2.0F Disk 1, cách làm này khiến cả 402.432 byte không được dùng làm tệp thật cũng bị sao chép theo
- Trong quy trình chuẩn bị đĩa master, cần format hoàn toàn đĩa trước khi chép các tệp game, và Sierra đã thực hiện đúng bước này với phần lớn đĩa game gốc khác
- Riêng với Space Quest II 2.0D Disk 1, có vẻ ai đó đã bỏ quên bước format này, và chính đĩa đó tiếp tục được dùng cho bản 2.0F
- Kết quả là có khả năng hàng chục nghìn đĩa SQ2 đến tay khách hàng và cửa hàng bán lẻ đã chứa ẩn 70% mã nguồn trình thông dịch AGI
Một trường hợp khảo cổ số chỉ được biết tới vào năm 2016
- Gần như chắc chắn đây là một sai sót ngoài ý muốn, và dường như Sierra, đối thủ cạnh tranh lẫn khách hàng vào thời điểm đó đều không nhận ra
- Phát hiện được biết đến đầu tiên là của người dùng trực tuyến NewRisingSun vào tháng 10/2016
- Việc chuyện này xảy ra vào cuối thời kỳ AGI cũng là điểm quan trọng
- Tháng 3/1988, Sierra đã phát triển xong hệ thống game phiêu lưu SCI
- Họ đang chuẩn bị phát hành King’s Quest IV, trò chơi đầu tiên dùng SCI
- Nếu thời điểm mã nguồn trình thông dịch AGI có thể bị lộ do nhầm lẫn này xảy ra sớm hơn chỉ 1–2 năm, vấn đề có thể đã nghiêm trọng hơn
- Mã nguồn trình thông dịch AGI được trích xuất đã được tải lên kho lưu trữ GitHub
- Bản triển khai AGILE, một trình thông dịch AGI chạy trên web, ban đầu cũng nhận được một phần trợ giúp từ mã nguồn AGI gốc
1 bình luận
Ý kiến trên Hacker News
Bản DOS năm 1989 của Double Dragon II: The Revenge được phát hành trên 2 đĩa mềm, trong đó một đĩa có toàn bộ mã nguồn nằm dưới dạng một tệp nén đã bị xóa
Nó không hiện trong lệnh
DIR, nhưng có thể khôi phục dễ dàng: https://tcrf.net/Double_Dragon_II:The_Revenge(DOS)Buồn cười là ngay cả vào thời mà đúng nghĩa từng byte đều là tiền, vẫn có khá nhiều trường hợp các mục FAT của ai đó bị ghi hẳn vào cartridge
https://forums.nesdev.org/viewtopic.php?t=17324
Hẳn là sau khi hoàn thiện game, họ tạo một dạng đĩa master rồi gửi tới cơ sở sản xuất hàng loạt; vậy làm sao tệp nén đã xóa lại lọt vào master được nhỉ? Có khi nào họ vô tình chép vào rồi xóa trước khi phát hành không
Game đầu tiên cũng là Spacewar! bản DOS trên cùng chiếc máy đó. Nếu tôi nhớ đúng thì khi tới boss game bị đứng nên tôi không phá đảo được Double Dragon II, nhưng đó là một kỷ niệm đẹp
Gần đây tôi làm khá nhiều dịch ngược ROM synthesizer
ROM Yamaha DX9 có một mẩu bảng symbol firmware nằm trong phần trống còn sót lại của binary[0], và còn có cả một khối lớn mã 6303 có vẻ đến từ hệ thống phát triển. Tình cờ phát hiện những thứ như vậy thật sự đem lại cảm giác rất kinh ngạc. Tôi đã quá mê mảng mảng này đến mức cảm thấy mình như một nhà khảo cổ phần mềm đang hé nhìn vào quá khứ, rồi sa vào một cái hang thỏ sâu để tìm xem Yamaha đã dùng công cụ phát triển nào. Tôi không tìm được gì chắc chắn, nhưng đọc tài liệu về công cụ phát triển thời đó khiến tôi biết ơn hơn các workflow hiện đại
0: https://ajxs.me/blog/Hacking_the_Yamaha_DX9_To_Turn_It_Into_...
Tôi đã làm rất nhiều phân tích I/O thô và sector đĩa thô bằng BeBox, và BeOS có những công cụ rất tốt cho việc hack hệ thống tệp. Nhờ đó tôi tạo được một driver hệ thống tệp cho Windows, hoạt động tốt đến mức nhận được sự ủng hộ của Yamaha. Nếu một ngày nào đó bạn có hứng dịch ngược ROM Yamaha dành cho A-sampler thì hãy liên hệ. Tôi rất quan tâm đến lĩnh vực này. Công việc với DX9/DX7 cũng rất tuyệt, và với tư cách người đã dùng cả hai synthesizer từ thời chúng mới ra mắt, tôi thấy nó thật sự thú vị
Game này chiếm một vị trí quá mạnh mẽ trong tuổi thơ tôi, đến mức khi nghĩ lại sau ngần ấy thời gian, nó lại có cảm giác như một giấc mơ
Nếu tưởng tượng rằng trong cuộc sống hiện tại mình có cùng kiểu cảm giác kết nối với một game nào đó thì thấy gần như bất khả. Mọi thứ xung quanh chỉ giống như game, chương trình, đồ vật; còn Space Quest 2, 3, 4 thì đan vào như một phần căn bản trong DNA của tôi
Các game Sierra thời đó thật sự đặc biệt. Tôi đặc biệt chơi rất nhiều Police Quest II, LSL III, Hero's Quest vào khoảng cùng thời điểm. Những game Sierra EGA dựa trên văn bản có một thứ gì đó rất kỳ diệu, và với tôi đó là điểm cân bằng vừa đúng về kết nối cảm xúc và sáng tạo giữa Infocom và các bản VGA point-and-click về sau
Space Quest cũng gắn với một trong những câu chuyện Internet sơ khai yêu thích nhất của tôi. Vào thời các website chủ yếu được host trên Geocities và bởi các sinh viên đại học rảnh rỗi, có một fan site Space Quest; tôi đã gửi email cho người quản lý một trong những site SQ lớn, nói rằng tôi thích game và trang web đó. Khi ấy tôi khoảng 14 tuổi, và anh ấy trả lời rằng có thể gửi cho tôi các bản game gốc với giá khoảng 40 đô la. Đó là tất cả các bản gốc, có hộp và đĩa mềm nguyên bản. Khoảng năm 1997, tôi hơi lo khi gửi 40 đô la cho một người lạ ở tận đầu kia đất nước và kỳ vọng họ thật sự gửi đồ, nhưng anh ấy thực sự đã gửi. Vài tuần sau, tất cả game đến nơi đúng như mô tả, và tôi vui khôn tả. Chỉ sau một đêm tôi đã trở thành một tín đồ thật sự, và đó vẫn là ký ức như lõi mặt trời của sự lạc quan mà tôi còn giữ đến giờ. Jess, nếu bạn ở đâu đó ngoài kia, bạn là người thật. Hy vọng một ngày nào đó chúng ta gặp lại
Bố tôi làm ở nhà máy thép và quen với người phụ trách máy tính ở đó; người này đưa cho ông một bản SQ2 để đem về nhà chơi thử. Tôi chơi game đó điên cuồng, nhưng vì còn khá nhỏ nên rất nhiều chỗ làm tôi bối rối. Khi thật sự bị kẹt, tôi nhờ bố hỏi người phụ trách máy tính kia cách vượt qua một đoạn cụ thể, và hình như ông ấy tốt bụng đưa ra gợi ý thay vì nói thẳng đáp án. Đã khoảng 35 năm trôi qua, nhưng tôi vẫn nhớ khá chi tiết cả những giấc mơ mình từng mơ liên quan đến game đó. Nó thật sự có ảnh hưởng rất lớn
SQ I thì mãi sau này tôi mới chơi, còn SQ III không chạm tới tôi mạnh đến thế. Các phần còn lại thì thậm chí không còn là game EGA nhập lệnh bằng văn bản nữa. SQ II gợi lại rất nhiều ký ức, và tôi cũng học được phần nào tiếng Anh từ nó. Tôi vẫn nhớ cảm giác thỏa mãn khi phát hiện ra có thể bảo Roger Wilco “rub berries”
Đây là lần đầu tôi chơi kiểu game như vậy, và hồi khoảng mười tuổi tôi đã bám lấy nó suốt nhiều tuần
Tôi không cho rằng trong engine AGI có thứ bí quyết bí mật đặc biệt đến mức đối thủ có thể hưởng lợi từ việc rò rỉ
Có thể còn ví dụ khác, nhưng Hugo's House of Horrors là một game kiểu AGI do một người làm ra vài năm sau đó. Vượt qua sự mới lạ ban đầu của thể loại phiêu lưu đồ họa, các game của Sierra thành công vì họ bỏ công sức khổng lồ vào việc tạo đồ họa và viết nên game thực tế. Không có nghĩa là công nghệ chẳng là gì, nhưng tỷ trọng của nó trong sản phẩm cuối cùng thì khá nhỏ
Học và tạo ra phần mềm chạy được khó hơn ngày nay rất nhiều, và hầu như không có gì để làm nền tảng. Trên MS-DOS gần như không có mã nguồn mở đáng kể, càng không có engine game mã nguồn mở. Trong môi trường như vậy, nếu mã nguồn AGI bị rò rỉ rộng rãi, ít nhất nó có thể khá có ý nghĩa như một bản thiết kế cho thấy chính xác các game PC phổ biến nhất thời đó được tạo ra như thế nào
Đặc biệt nếu đó là mã không chứa bí mật mà hacker có thể lợi dụng, như khóa hay backdoor. Mã bị rò rỉ dĩ nhiên không có giấy phép, nên nếu muốn tránh kiện tụng thì không thể tái sử dụng nguyên xi trong sản phẩm của mình. Rốt cuộc phải đọc mã đó, hiểu kỹ thuật, rồi áp dụng vào công việc của mình sao cho không có mùi vi phạm bản quyền, mà thường việc này còn khó hơn làm từ đầu. Ngay cả khi có trường hợp thuận lợi, tôi cũng nghi ngờ không biết nó thường xuyên chuyển thành lợi thế cạnh tranh thực sự đến mức nào. Lập trình viên vẫn hay viết mã mới dù có mã nguồn mở được tài liệu hóa tốt và có giấy phép dễ dãi. Đọc mã thường khó hơn viết mã, và đôi khi chỉ việc build lại cũng đã khó. Nó có thể khiến việc sao chép dễ hơn một chút, nhưng game thường bị crack và phát tán trong vài ngày, và mã chống sao chép có thể cũng không nằm trong mã nguồn
Bản thân số người nói được các ngôn ngữ đó có lẽ đã ít hơn vài bậc độ lớn, và số người có thể dùng chúng để tạo ra một thứ nhất quán còn ít hơn nữa
Ngày nay nó đang giảm nhanh, nên những thứ ta tiếp xúc hiện giờ không còn có sức định hình các trọng số bên trong mạnh như khi ấy
Chú thích lịch sử thay đổi thật sự rất hay
Trong thời kỳ trước rất lâu khi các công cụ quản lý mã nguồn có thể hiển thị rõ ràng những thứ như thế này, nó cho thấy mức độ tỉ mỉ và tinh thần thủ công rất cao. Thành thật mà nói, ngay cả sau CVS/SVN/Git, điều này vẫn chưa rõ ràng với nhiều người. Bài này cũng gợi tôi nhớ đến bài viết nổi tiếng ‘No Silver Bullet’[1] năm 1986, dự đoán rằng phần mềm trong tương lai về cơ bản vẫn sẽ được lập trình viên khổ công viết từng lệnh như khi đó. Việc mã engine game và chú thích trong bài gốc giống với thứ hôm nay tôi có thể viết, theo tôi, gần 40 năm sau vẫn ủng hộ dự đoán đó
[1] https://en.wikipedia.org/wiki/No_Silver_Bullet
Bản Air Fortress trên Famicom có nhiều thứ vô tình lọt vào ROM đến mức phi lý
Trong đó có mã ASM chưa được biên dịch, danh sách thư mục MS-DOS, các chuỗi từ một trong những file EXE dùng để build game, và nhiều thứ khác. Băng game bản Nhật là 128+128KB. Sau đó khi làm bản NES cho Mỹ, phần lớn 128KB dữ liệu đồ họa là đồ họa trùng lặp hoặc không dùng, còn đồ họa độc nhất thực sự chỉ khoảng 36KB. Họ loại bỏ hình ảnh một hành tinh trong một đoạn kết để giảm đồ họa xuống 32KB, và phát hành bằng băng 128+32KB thay vì băng 128+128KB
Source: https://tcrf.net/Air_Fortress
Những tình huống như thế này thực ra xảy ra rất thường xuyên
The Cutting Room Floor liệt kê khoảng 500 trường hợp, từ chỉ có một ít mã vô tình được đưa vào cho đến gần như toàn bộ mã
https://tcrf.net/Category:Games_with_uncompiled_source_code
Tôi cũng tò mò liệu mình có cùng nhận định không. Chuyện tương tự cũng xảy ra với đĩa King's Quest III, và thực ra có vẻ diễn ra gần như cùng thời điểm với trường hợp Space Quest II
Phần tôi thích nhất là có vẻ như suốt cả một thế hệ, không ai phát hiện mã nguồn nằm trên đĩa
“Đáng kinh ngạc là dường như cả Sierra, đối thủ cạnh tranh lẫn khách hàng đều không nhận ra chuyện này đã xảy ra, và nó chỉ được phát hiện sau hàng chục năm. Phát hiện đầu tiên được biết đến là của người dùng online NewRisingSun vào tháng 10 năm 2016.” Điều này cũng khiến tôi nhớ đến những đột phá gần đây của Tetris và Super Mario Bros. Khi chơi những game này hồi nhỏ, tôi từng nghĩ rằng sau vài chục năm chúng sẽ còn lại như những di vật bị lãng quên, đến mức ngoài những người đam mê tận tụy nhất thì khó ai còn chạy được. Thế nhưng Internet và trình giả lập đã thổi sức sống mới vào các game và điện toán thời kỳ đầu đó
Chắc chắn đã có người phát hiện các file bị xóa, nhưng trước khi Internet phổ biến, rất có thể chuyện đó không được biết đến rộng rãi hay được ghi lại
Có thể ai đó đã phát hiện dữ liệu còn sót trong vùng trống khi imaging những chiếc đĩa này
Từ năm 1987 đến 1993, tôi đã chuẩn bị khoảng chín đĩa master cho hai ứng dụng Mac
Tôi luôn dùng đĩa mềm mới, và có một checklist dài để xác nhận đĩa là đúng. May mắn là tất cả đều ổn, đặc biệt một số đĩa đã được dùng để tạo ra 100.000 bản đĩa. Thật mừng là giờ không còn ai phải làm việc kiểu này nữa
Tôi từng thấy những lớp như thế này: base, thêm công cụ, thêm mã nguồn, biên dịch, xóa mã nguồn, xóa công cụ bổ sung, phát hành. Đại loại như tình huống “Sao Docker image lại to thế này? Thôi thì dung lượng lưu trữ cũng rẻ mà...”. Cũng có giải pháp dễ như build đa giai đoạn ( https://docs.docker.com/build/building/multi-stage/ ). Nhưng nếu không biết rằng view hiện tại của Docker image bao gồm tất cả các lớp trước đó, đôi khi vẫn sẽ mắc lỗi
Vào thời còn tạo artifact phát hành bằng tay, thường có những thứ sót lại vốn không định đưa vào bản phát hành
Chẳng hạn như nội dung bị cắt[1] hay debug symbol[2]. Khi tôi tình cờ phát hiện debug symbol ẩn trong kho lưu trữ dữ liệu của bản demo một trò chơi điện tử mà tôi đang reverse engineering, điều đó thật bất ngờ nhưng cực kỳ hữu ích. Ngày nay, nhờ CI/CD, build tự động và các thực hành phát triển hiện đại khác, khả năng chuyện này xảy ra có lẽ thấp hơn
[1] https://tcrf.net
[2] https://www.retroreversing.com/games/symbols
Nếu không có lỗi, sẽ chẳng ai xem qua hàng nghìn dòng output console. Ngay cả khi gói phát hành cuối cùng chứa quá nhiều thứ không cần thiết, các bài test vẫn có khả năng pass. Vì vậy trực giác của tôi lại nghiêng về điều ngược lại. Chuyện này có thể xảy ra thường xuyên hơn, hoặc ít nhất CI/CD cũng có khả năng khiến những việc như vậy dễ xảy ra hơn so với build thủ công. Cũng có thể còn những yếu tố khác