امنیت، هویت، استقرار و تابآوری · فصل ۷ — Dependency، Contract، Event و Network Failure · 111
Dependency and Toolchain Mismatch
Reproduce a dependency/toolchain mismatch in a deterministic local fixture, identify the first divergent layer, separate package resolution from runtime/toolchain state, and choose containment or repair evidence without guessing from the final error alone. میتواند failure family «Dependency/Toolchain Mismatch» را بازتولید/تشخیص دهد و detection، containment و recovery مناسب را تعیین کند.
Lesson summary
Reproduce a dependency/toolchain mismatch in a deterministic local fixture, identify the first divergent layer, separate package resolution from runtime/toolchain state, and choose containment or repair evidence without guessing from the final error alone.
میتواند failure family «Dependency/Toolchain Mismatch» را بازتولید/تشخیص دهد و detection، containment و recovery مناسب را تعیین کند.
This lesson produces
میتواند failure family «Dependency/Toolchain Mismatch» را بازتولید/تشخیص دهد و detection، containment و recovery مناسب را تعیین کند.
Who it is for
Foundation
Use a guided evidence table and one explicit misconception repair.
Repair
Re-run only the failed evidence dimension with a smaller fixture and contrast case.
Experienced
Start from ambiguous signals; require competing hypotheses, negative evidence and transfer.
Prerequisites
1. What is the actual failure?
Two developers have checkouts that look identical. Tests pass on one workstation, while the same command fails on the other with a loader or runtime incompatibility. The visible error may occur at the end of the chain, but a defensible cause must be traced through evidence layers. In this lesson, a Dependency and Toolchain Mismatch is a disagreement between declared environment state and the state actually resolved or executed that can explain the failure. The goal is not to guess from the final error string; it is to build a reproducible evidence chain.
2. Split the environment into independent layers
Keep at least these layers separate: declared direct dependencies, the actually resolved dependency tree, package-manager version/metadata, runtime or tool executable, and platform/native boundary. Two machines can have the same manifest while resolving a different transitive package. They can also have the same lockfile while executing under a different runtime major. Collapsing all of these into one label called “the environment” hides the first divergence.
3. What does a lockfile prove—and not prove?
Official npm documentation describes package-lock.json as recording an exact generated dependency tree to support repeatable dependency installs [NPM-LOCK]. That statement is bounded to npm package-tree resolution. A lockfile by itself does not prove OS version, runtime version, compiler, the executable selected from PATH, native ABI, or an external service. “The lockfile is identical” is useful evidence, not proof of complete toolchain equivalence.
4. Build an environment fingerprint
Before repair, capture a minimal fingerprint: manifest/constraints, lock or resolved-tree identity, package-manager name/version, runtime name/version, tool executable identity, platform/architecture marker, and any relevant native-addon marker. The fingerprint must distinguish observation from inference. “Node is probably wrong” is an inference; runtime_major=20 versus runtime_major=18 is an observation.
5. Reproduce before you repair
If the failure was seen once in a noisy workstation state, causal diagnosis is premature. Shrink the fixture, hold inputs and command constant, and reproduce the symptom at least twice under defined conditions. Cache, generated files, and retained state must be controlled or explicitly recorded as unknown. Multiple repair attempts before reproduction is stable destroy useful evidence.
6. Locate the first divergence that can explain the failure
Move from earlier to later layers. If the manifest is equal but the resolved tree differs at one transitive package and a controlled probe ties that difference to the failure, you do not need to declare the runtime guilty as well. Stop at the earliest observed divergence that can explain the failure and keep later layers unproven until needed. This is a bounded-diagnosis rule, not a claim that every failure has one cause.
7. Transitive resolution drift
A common mismatch keeps direct dependencies identical while the resolved tree differs. The drift can come from incomplete locking, a different resolution policy, or retained state. A useful probe changes only resolution while holding runtime and platform constant. If restoring the baseline tree removes the failure and reintroducing the mutation restores it, causal support becomes substantially stronger.
8. Separate runtime and tool executable from package resolution
Sometimes the dependency tree is identical but the runtime major or actual executable differs. For example, both fixtures can contain identical packages while one executes with runtime 18 and the other with runtime 20, and the synthetic fixture is deliberately valid only under 18. Reinstalling packages is then not a targeted repair. Evidence should show that package resolution stayed fixed while the runtime/tool layer diverged.
9. Platform and native boundary
A JavaScript-level dependency tree can be identical while a native addon or platform marker differs. Architecture, OS, ABI, or binary target can fail before application logic runs. When the platform/native marker is the first divergence that can explain the symptom, repair should target that boundary. Changing unrelated packages is symptom hunting rather than bounded diagnosis.
10. Not every divergence is causal
A package-manager metadata field may differ while the resolved tree, runtime, platform, and observed symptom remain identical. The difference is real, but there is no evidence that it explains the failure. Record the divergence while rejecting or leaving causal support OPEN. Professional diagnosis distinguishes “something differs” from “this difference explains the failure.”
11. The warm-cache and green-reinstall trap
Suppose a reinstall turns green because a compatible artifact already exists in a warm cache. The green rerun may suppress the symptom without establishing a cause. Closure needs a recurrence probe: reintroduce the mutation, or rebuild the cache state under control, and require the sensor to observe the failure again. If recurrence cannot be shown, the repair remains unclosed.
12. Containment is not repair
Containment should be reversible and bounded: run the task on the supported runtime, temporarily pin a known resolution, or disable the incompatible native path inside the fixture. Repair corrects the supported causal boundary and is independently verified. Containment reduces exposure; repair restores a defensible environment state.
13. What counts as repair proof?
A strong repair has four pieces: a reproducible baseline failure, a limited change tied to the supported divergence, an independent rerun that removes the symptom, and a recurrence test that sees the failure again when the mutation returns. If only the green rerun exists, hidden state may still be responsible and causal closure is not justified.
14. Dependency Divergence Diagnosis Record v1
For every case, fill eight evidence dimensions: layer_identity, declared_vs_observed, reproduction, first_divergence, causal_support, containment, repair_rerun, and unknowns. Keep direct observations separate from inference. When evidence is incomplete, preserve OPEN and state exactly what is required for closure. The record is not a root-cause story; it is an auditable boundary for a technical decision.
15. Transfer: a different package manager, the same evidence standard
The transfer fixture changes the package manager and runtime marker. Do not copy npm-specific conclusions. Rebuild the fingerprint, separate resolved state from runtime/tool state, and identify the first divergence that can explain the failure. If runtime is the first supported divergence, record it even when tool metadata also differs. The transferable skill is the evidence method, not the product name.
Assessment
There is no answer key in this lesson pack; answer it yourself and mark honestly. "Needs review" sends the lesson to your review queue.
FLR-001-AF1 formative
FLR-001-AF2 formative
FLR-001-AF3 formative
FLR-001-S1 retrieval
FLR-001-S2 application
FLR-001-S3 diagnosis
FLR-001-S4 decision
FLR-001-S5 transfer
Assessment rubric
| Dimension | Sufficient evidence | Blocking failure |
|---|---|---|
| Reproduction + identity | Fixture/environment identity is explicit and the symptom is reproducible when claimed | Diagnosis starts from an unreproduced final error |
| Evidence discrimination | Declared, resolved, tool/runtime, and platform layers are separate; one alternative is rejected | One artifact such as a lockfile produces complete causal closure |
| First divergence + causal support | The earliest divergence that can explain the symptom is identified and later layers remain bounded | Every observed difference is labeled causal |
| Containment + repair proof | Containment is reversible; repair has independent rerun and recurrence evidence | Green reinstall/rerun alone treated as proof |
| Transfer | Alternate-manager case is rebuilt from changed evidence | npm-specific classification copied without new evidence |
References & freshness
Case studies
Same manifest, different transitive resolved version; runtime/platform held constant.
Package-manager metadata differs but symptom and execution state do not; divergence is non-causal.
Warm cache makes reinstall green; recurrence remains untested.
Different package manager and runtime marker require rebuilding the evidence chain rather than copying npm conclusions.
Lesson visuals
Lab files
Use the eight deterministic synthetic fixtures in fixtures/cases.json.
For each case:
- identify the evidence layer being compared;
- separate declared state from observed/resolved/executed state;
- confirm whether the symptom is reproducible;
- locate the earliest divergence that can explain the failure;
- record negative evidence that weakens at least one alternative;
- choose reversible containment before broader repair;
- require an independent rerun plus recurrence test for repair closure; and
- preserve missing runtime/platform facts as OPEN rather than guessing.
Implement build_record(case) in starter.py. The learner files contain no hidden expected classifications. Everything is local, synthetic, and offline.