بازگشت به مهندسی مدرن و کار با هوش مصنوعی · فصل ۵ — Shell، Workspace، Lockfile و Build Closure · 26
Cargo Workspace و Rust Build/Test
میتواند «Cargo Workspace و Rust Build/Test» را در یک workspace محدود طوری پیکربندی کند که dependency/toolchain state قابل تکرار و قابل بررسی باشد.
خلاصهٔ درس
میتواند «Cargo Workspace و Rust Build/Test» را در یک workspace محدود طوری پیکربندی کند که dependency/toolchain state قابل تکرار و قابل بررسی باشد.
خروجی این درس
میتواند «Cargo Workspace و Rust Build/Test» را در یک workspace محدود طوری پیکربندی کند که dependency/toolchain state قابل تکرار و قابل بررسی باشد.
Cargo.lock ثابت و تست سبز هنوز compiler را ثابت نمیکند
یک workspace دو crate دارد، Cargo.lock commit شده و cargo test روی لپتاپ توسعهدهنده سبز است. روی ماشین تمیز، همان lock باقی میماند اما rust-toolchain.toml toolchain دیگری را انتخاب میکند؛ در سناریوی دیگری یکی از dependencyهای محلی موجود نیست. این دو شکست از یک لایه نیستند. lock وضعیت dependencyهای Cargo را محدود میکند، نه هویت rustc یا موجودبودن همه ورودیهای محلی/سیستمی را.
خروجی این درس Cargo Workspace Build Evidence Record v1 است: memberهای workspace، hash فایل lock، هویت cargo/rustc/rustup، toolchain فعال و فایل انتخاب آن، مرز dependency محلی، نتیجه build/test در حالت locked/offline، دامنه تستشده و residual system boundary را کنار هم ثبت میکند.
سه مسیر، یک evidence bar
در Foundation ابتدا memberها، lock و toolchain را جدا روی نقشه ثبت کن. در Repair فقط کوچکترین mismatch را جدا کن: lock drift، toolchain selection یا local availability. در Experienced/Fast Path میتوان walkthrough دستورها را حذف کرد، اما hashها، هویت ابزارها، clean target، mutation و residual-risk statement حذف نمیشوند.
مدل ذهنی: workspace → lock + toolchain → local inputs → build/test evidence
Cargo.toml ریشه، مرز workspace و memberها را تعریف میکند. memberهای workspace یک Cargo.lock مشترک در ریشه دارند، اما Rust toolchain از مسیر جداگانهای مانند rust-toolchain.toml، override یا انتخاب rustup تعیین میشود. build سپس lock، toolchain، sourceها و dependencyهای در دسترس را مصرف میکند. cargo test هم فقط رفتارهایی را که test targetها واقعاً اجرا میکنند پوشش میدهد.
پس چهار گزاره را یکی نکن: «dependency resolution ثابت است»، «compiler/toolchain مشخص است»، «ورودیهای لازم محلی موجودند» و «تستهای فعلی سبز هستند». هرکدام evidence مستقل میخواهد.
Cargo Workspace Build Evidence Record v1
برای هر probe این فیلدها را ثبت کن: workspace_members، cargo_lock_hash، cargo_identity، rustc_identity، rustup_active_toolchain، toolchain_file_hash، local_dependency_boundary، locked_offline_build، test_result، tested_scope و residual_system_boundary. هر نتیجه باید OBSERVED، INFERRED یا UNKNOWN باشد و به evidence ref وصل شود.
اول member set را ثابت کن، سپس lock و toolchain را جدا ثبت کن. بعد از پاککردن target/، build/test را در مرز --locked --offline اجرا کن. اگر ابزار یا toolchain لازم در ماشین موجود نیست، همان را بهعنوان evidence ثبت کن؛ نتیجه سبز جعل نمیشود.
semantics فعلی Cargo و rustup در محدوده این درس
مستندات فعلی Cargo میگویند workspace مجموعهای از package/memberهاست و یک Cargo.lock مشترک در ریشه دارد. --locked الزام میکند dependencyها و versionها مطابق lock موجود بمانند و اگر lock گم باشد یا نیاز به تغییر داشته باشد command fail میشود. --offline دسترسی شبکه Cargo را ممنوع میکند و آن را به دادههای محلی موجود محدود میکند. در Cargo، --frozen معادل ترکیب همین دو constraint است؛ این معنی را نباید از uv یا pnpm قرض گرفت.
rustup لایه دیگری است. انتخاب toolchain میتواند از shorthand خط فرمان، متغیر محیطی، directory override، rust-toolchain.toml یا default toolchain بیاید. rustup show evidence مستقیمی برای active toolchain میدهد. بنابراین ثابتماندن Cargo.lock بهتنهایی ثابت نمیکند rustc همان قبلی است.
cargo test نیز scope دارد. سبز بودن test suite نشان میدهد test targetهای اجراشده در context ثبتشده pass شدهاند؛ رفتارهای تستنشده، native/linker state یا deployment environment از این نتیجه نتیجهگیری نمیشوند.
سه مثال که failure layer را جدا میکنند
Baseline: workspace مجازی دو member دارد. hash ریشه Cargo.toml و Cargo.lock، هویت cargo/rustc/rustup و toolchain ثبت میشود. target/ پاک میشود و cargo build --workspace --locked --offline و سپس cargo test --workspace --locked --offline اجرا میشوند. نتیجه فقط برای همین context معتبر است.
Manifest–lock drift: version یکی از memberها را در manifest تغییر بده ولی lock را regenerate نکن. اگر build locked برای حفظ lock نیاز به update داشته باشد، failure مربوط به LOCK_CONSISTENCY است؛ راه درست verification این نیست که lock را بیصدا refresh کنیم.
Toolchain mutation با lock ثابت: Cargo.lock را دست نزن و فقط declaration فایل toolchain را تغییر بده. حتی قبل از build، evidence record باید تغییر کرده باشد، چون compiler-selection claim عوض شده است. اگر toolchain جدید نصب نیست، نتیجه TOOLCHAIN_UNAVAILABLE_OR_MISMATCH است نه «lock خراب».
چهار shortcut که اعتماد کاذب میسازند
«Cargo.lock یعنی rustc هم pin شده.» اصلاح: rustc --version و active rustup toolchain/file hash را مستقل ثبت کن.
«cargo test سبز است، پس برنامه درست است.» اصلاح: tested_scope و یک رفتار عمداً تستنشده را صریح نگه دار.
«--frozen در همه ابزارها یک معنی دارد.» اصلاح: semantics را از Cargo documentation خودش بخوان؛ در Cargo این flag ترکیب locked و offline است.
«offline failure یعنی lock اشتباه است.» اصلاح: lock را ثابت نگه دار و local dependency availability را جدا mutate کن. dependency محلی مفقود میتواند با lock کاملاً ثابت fail شود.
برای مهندس باتجربه: build evidence را قابل review کن
در CI، hash Cargo.lock را کنار cargo --version، rustc --version و active toolchain نگه دار. تغییر lock و تغییر rust-toolchain.toml دو artifact review مستقلاند. clean target/ و --locked --offline cache/build residue را کمتر مبهم میکنند، اما system linker، native libraries، target-specific toolchains و build-script side effects همچنان باید بهعنوان residual boundary ثبت شوند.
برای monorepoهای بزرگ، package selection را نیز evidence کن؛ سبز بودن یک default-member به معنی build/test همه workspace نیست.
pin دقیق در برابر هزینه نگهداری
Pin کردن toolchain به release مشخص میتواند drift compiler را کم کند، اما نیازمند availability و نگهداری آن toolchain است. استفاده از stable سادهتر است ولی identity دقیق زمانمندتر میشود؛ در هر دو حالت record باید آنچه واقعاً فعال شده را ثبت کند.
--offline برای verification مفید است، اما فقط availability محلی Cargo را میسنجد و closure کامل OS/linker را نمیدهد. vendor کردن dependencyها یا cache آماده میتواند محیط disconnected را عملیتر کند، ولی provenance و update workflow خودش را میطلبد. این درس ادعای bit-identical binaries ندارد.
Lab: workspace کوچک، mutationهای مستقل
از TOL005-LAB1 استفاده کن. python setup_fixture.py یک working copy تازه با دو workspace member و یک path dependency محلیِ خارج از member set میسازد. python inspect_context.py memberها، hashها، هویت ابزارها و مرز resolveشده dependency محلی را ثبت میکند. اگر Cargo/Rust/rustup و toolchain اعلامشده بهصورت محلی موجود باشند، python run_cargo_probe.py baseline ابتدا target/ را پاک میکند و build/test locked-offline را اجرا میکند. سپس هر mutation را پس از reset جدا اجرا کن: manifest-lock-drift، toolchain-change، missing-local-dep و untested-behavior. mutation مربوط به missing-local-dep فقط dependency محلیِ غیرعضو را حذف میکند تا member set ثابت بماند.
Lab به network نیاز ندارد. runner قبل از toolchain mutation بررسی میکند declaration جدید locally available هست یا نه و برای نصب toolchain به شبکه متوسل نمیشود. اگر cargo یا rustup در authoring/learner environment موجود نیست، حالت RUST_TOOLCHAIN_UNAVAILABLE ثبت میشود و runtime evidence ساخته نمیشود.
حداقل evidence قابل دفاع
member set و root manifest، hash Cargo.lock، identityهای cargo/rustc/rustup، active toolchain و hash فایل toolchain، وضعیت dependencyهای محلی، clean-target declaration، command/result locked-offline، test result، tested scope و residual system boundary را نگه دار.
failure layerهای این درس حداقل شامل WORKSPACE_MEMBERSHIP، LOCK_CONSISTENCY، RUST_TOOLCHAIN_IDENTITY، LOCAL_DEPENDENCY_AVAILABILITY، BUILD_EXECUTION، TEST_SCOPE، SYSTEM_RESIDUAL و UNKNOWN_OR_MULTIPLE هستند. strongest green claim محدود است: workspace ثبتشده با lock/toolchain/inputهای ثبتشده build شد و test targetهای ثبتشده pass شدند.
ارزیابی: diagnosis، decision، application و transfer
AS1: lock ثابت است ولی rust-toolchain.toml تغییر کرده. کوچکترین boundary تغییرکرده و evidence لازم را مشخص کن.
AS2: تیم Cargo.lock و یک log سبز cargo test دارد، اما member set، rustc/rustup identity و offline/local availability را ثبت نکرده است. برای Build Evidence Record تصمیم ACCEPT، REJECT یا DEFER بده و residual risk را بنویس.
AS3: fixture را اجرا کن، matrix را کامل کن و lock-drift، toolchain-change و missing-local-dependency را مستقل طبقهبندی کن.
AS4: در workspace دوم toolchain declaration عوض شده و یک dependency محلی حذف شده است. بدون sequence hint توضیح بده کدام evidence قبلی هنوز معتبر است، کدام invalid شده و چه چیزی باید دوباره verify شود.
مرز منبع و تازگی
ادعاهای وابسته به ابزار به مستندات رسمی Cargo و rustup محدودند و در 2026-09-09 دوباره بررسی شدهاند. مستندات فعلی Cargo همچنان shared workspace lock را توضیح میدهند، --locked و --offline را جدا تعریف میکنند و --frozen را ترکیب آن دو میدانند. مستندات rustup نیز precedence انتخاب toolchain و rust-toolchain.toml/overrideها را جدا از Cargo.lock مستند میکنند.
تاریخ review بعدی Bible 2026-10-17 است. اگر semantics flagها، workspace selection یا rustup override precedence تغییر کند، فقط source layer volatile باید refresh شود؛ scope درس به total system reproducibility یا correctness کامل گسترش نمییابد.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
AS1 diagnosis
AS2 decision
AS3 application
AS4 transfer
ملاکهای ارزیابی (rubric)
- Boundary correctness (critical): member/lock/toolchain/local-input/test boundaries are separated; no silent scope expansion.
- Evidence traceability (critical): every material conclusion points to an observable or is explicitly UNKNOWN.
- Mutation robustness (critical): lock drift, toolchain change, and missing local dependency are classified at the correct layer.
- Transfer and residual risk: changed-context reasoning adapts the method and states what remains unproven.
A green cargo test alone cannot satisfy the rubric.
منابع و تازگی
مطالعهٔ موارد (case studies)
فایلهای آزمایشگاه
این Lab شواهد workspace/lock کارگو را از هویت Rust toolchain و موجودبودن path dependency محلیِ غیرعضو جدا میکند.
python setup_fixture.pypython inspect_context.pypython run_cargo_probe.py baseline- پیش از هر mutation reset کن:
manifest-lock-drift،toolchain-change،missing-local-dep،untested-behavior.
math_core و cli_app دو member ثابت workspace هستند و text_fmt یک path dependency محلی خارج از member set است. mutation مربوط به missing-local-dep فقط text_fmt را حذف میکند.
شبکه لازم نیست و runner هیچ toolchain مفقودی را نصب نمیکند. نبود Cargo/Rust، نبود شواهد انتخاب toolchain از rustup یا نصبنبودن toolchain اعلامشده با status غیرصفر fail-closed ثبت میشود و نباید بهعنوان build/test سبز تفسیر شود.
رسانه و اسلایدهای درس
فایلهای آموزشی (دانلود)