diff --git a/AGENTS.md b/AGENTS.md index 4c4b484..1644f15 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -71,6 +71,21 @@ Any organization that designs a system will produce a design whose structure is - Did a recent reorganization change communication paths this design assumes? - Is a team change being proposed in order to reshape the architecture, and is that stated as its intent? +## Current Stack +Each choice of language, runtime, framework, library, toolchain, or service is made on today's evidence of fit and upkeep, and a choice carried forward from an earlier design needs a reason that holds now; that it was already in use is not one. + +**Applies when** +- A design or change picks a language, runtime, framework, library, toolchain, or hosted service, including by extending an existing one. +- The incumbent choice is chosen in the proposal because other parts already use it, not because of what it offers now. +- The incumbent is past its support window, is no longer maintained, or no longer receives security fixes. +- A newer option has a maintained release line and a migration path whose cost can be estimated. + +**Ask** +- Which language, runtime, framework, library, toolchain, or service does this design choose, and is each maintained today, judged by its release history, support window, and advisories? +- Where the choice is the one already in use, what current reason supports it other than that it was there? +- What would it cost to move to the alternative, and is that cost smaller or larger than the cost of staying put as the incumbent ages? +- Is the reason for the choice written where a later reader will find it, with the date it was judged? + ## Defense in Depth Protect critical assets and actions with multiple controls that fail differently and cover prevention, detection, containment, and recovery. diff --git a/QUICK_REFERENCE.md b/QUICK_REFERENCE.md index f04003e..162371f 100644 --- a/QUICK_REFERENCE.md +++ b/QUICK_REFERENCE.md @@ -11,6 +11,7 @@ Generated from `principles/*.toml`. Do not edit this file directly. | [Compromise Recording](principles/compromise-recording.toml) | Tamper-evident history; Append-only state; Record what cannot be prevented | principle | security, socio-technical | When a breach cannot be reliably prevented, make it reliably recorded somewhere the breaching party cannot rewrite. | governance; yes | | [Confused Deputy](principles/confused-deputy.toml) | Confused deputy problem; Confused deputy attack | anti-pattern | security, ai-harness | A privileged program acts on a resource its requester named, under its own authority, and so lends the requester reach nobody granted it. | runtime; partially | | [Conway's Law](principles/conways-law.toml) | Mirroring hypothesis; Organization-structure homomorphism | law | socio-technical, architecture | A system's real module boundaries settle where the designing organization's communication boundaries are, whatever the architecture diagram says. | review; partially | +| [Current Stack](principles/current-stack.toml) | Judge the stack afresh; Choose what is current, not what is inherited; Do not keep a choice because it was there | principle | architecture, evolution | When a design picks a language, runtime, framework, library, toolchain, or service, pick what is current and maintained today, judged afresh against the need; do not keep a choice only because it was already there. | review; partially; rung: text, semantic | | [Data Minimization](principles/data-minimization.toml) | Purpose limitation; Collect only what is needed; Publish only what is needed | principle | security, ai-harness | Collect, keep, and publish only the data a stated purpose requires. | lint; yes; rung: text | | [Defense in Depth](principles/defense-in-depth.toml) | Layered defenses; Fault containment; Blast radius | principle | security, reliability, ai-harness | Use independent controls so one failed assumption does not become complete compromise. | governance; partially | | [Deprecation Discipline](principles/deprecation-discipline.toml) | Compatibility budget; Semantic versioning; Dependency currency | practice | evolution, interfaces | Change a published interface through announced, versioned, time-boxed steps, and finish them; a deprecated path that is never removed is compatibility debt that keeps accruing. | lint; yes; rung: text | @@ -57,16 +58,16 @@ Generated from `principles/*.toml`. Do not edit this file directly. - **law**: [Conway's Law](principles/conways-law.toml), [Goodhart's Law](principles/goodharts-law.toml), [Hyrum's Law](principles/hyrums-law.toml) - **philosophy**: [Unix Composability](principles/unix-composability.toml) - **practice**: [Deprecation Discipline](principles/deprecation-discipline.toml) -- **principle**: [Acyclic Dependencies Principle](principles/acyclic-dependencies.toml), [Complete Mediation](principles/complete-mediation.toml), [Compromise Recording](principles/compromise-recording.toml), [Data Minimization](principles/data-minimization.toml), [Defense in Depth](principles/defense-in-depth.toml), [Economy of Mechanism](principles/economy-of-mechanism.toml), [End-to-End Principle](principles/end-to-end-principle.toml), [Enforcement Needs a Trigger](principles/enforcement-needs-a-trigger.toml), [Explicit Unknown](principles/explicit-unknown.toml), [Fail Fast and Explicitly](principles/fail-fast.toml), [Fail-Safe Defaults](principles/fail-safe-defaults.toml), [Follow Published Standards](principles/follow-published-standards.toml), [Graceful Degradation](principles/graceful-degradation.toml), [High Cohesion, Low Coupling](principles/high-cohesion-low-coupling.toml), [Host-Owned Logs](principles/host-owned-logs.toml), [Idempotency](principles/idempotency.toml), [Information Hiding](principles/information-hiding.toml), [Informed Consent for Consequential Actions](principles/informed-consent.toml), [Least Astonishment](principles/least-astonishment.toml), [Least Common Mechanism](principles/least-common-mechanism.toml), [Least Privilege](principles/least-privilege.toml), [Minimize Attack Surface](principles/minimize-attack-surface.toml), [Namespaced Identifiers](principles/namespaced-identifiers.toml), [Observability](principles/observability.toml), [Parameterize, Do Not Enumerate](principles/parameterize-do-not-enumerate.toml), [Psychological Acceptability](principles/psychological-acceptability.toml), [Reproducible Derived State](principles/reproducible-derived-state.toml), [Reuse Maintained Components](principles/reuse-maintained-components.toml), [Robustness Principle](principles/robustness-principle.toml), [Rule of Least Power](principles/least-power.toml), [Separate Mechanism from Policy](principles/mechanism-policy-separation.toml), [Separation of Concerns](principles/separation-of-concerns.toml), [Separation of Privilege](principles/separation-of-privilege.toml), [Single Authoritative Source](principles/single-authoritative-source.toml) +- **principle**: [Acyclic Dependencies Principle](principles/acyclic-dependencies.toml), [Complete Mediation](principles/complete-mediation.toml), [Compromise Recording](principles/compromise-recording.toml), [Current Stack](principles/current-stack.toml), [Data Minimization](principles/data-minimization.toml), [Defense in Depth](principles/defense-in-depth.toml), [Economy of Mechanism](principles/economy-of-mechanism.toml), [End-to-End Principle](principles/end-to-end-principle.toml), [Enforcement Needs a Trigger](principles/enforcement-needs-a-trigger.toml), [Explicit Unknown](principles/explicit-unknown.toml), [Fail Fast and Explicitly](principles/fail-fast.toml), [Fail-Safe Defaults](principles/fail-safe-defaults.toml), [Follow Published Standards](principles/follow-published-standards.toml), [Graceful Degradation](principles/graceful-degradation.toml), [High Cohesion, Low Coupling](principles/high-cohesion-low-coupling.toml), [Host-Owned Logs](principles/host-owned-logs.toml), [Idempotency](principles/idempotency.toml), [Information Hiding](principles/information-hiding.toml), [Informed Consent for Consequential Actions](principles/informed-consent.toml), [Least Astonishment](principles/least-astonishment.toml), [Least Common Mechanism](principles/least-common-mechanism.toml), [Least Privilege](principles/least-privilege.toml), [Minimize Attack Surface](principles/minimize-attack-surface.toml), [Namespaced Identifiers](principles/namespaced-identifiers.toml), [Observability](principles/observability.toml), [Parameterize, Do Not Enumerate](principles/parameterize-do-not-enumerate.toml), [Psychological Acceptability](principles/psychological-acceptability.toml), [Reproducible Derived State](principles/reproducible-derived-state.toml), [Reuse Maintained Components](principles/reuse-maintained-components.toml), [Robustness Principle](principles/robustness-principle.toml), [Rule of Least Power](principles/least-power.toml), [Separate Mechanism from Policy](principles/mechanism-policy-separation.toml), [Separation of Concerns](principles/separation-of-concerns.toml), [Separation of Privilege](principles/separation-of-privilege.toml), [Single Authoritative Source](principles/single-authoritative-source.toml) - **tactic**: [Backpressure](principles/backpressure.toml) ## By domain - **ai-harness**: [Complete Mediation](principles/complete-mediation.toml), [Confused Deputy](principles/confused-deputy.toml), [Data Minimization](principles/data-minimization.toml), [Defense in Depth](principles/defense-in-depth.toml), [Enforcement Needs a Trigger](principles/enforcement-needs-a-trigger.toml), [Explicit Unknown](principles/explicit-unknown.toml), [Fail-Safe Defaults](principles/fail-safe-defaults.toml), [Idempotency](principles/idempotency.toml), [Informed Consent for Consequential Actions](principles/informed-consent.toml), [Least Astonishment](principles/least-astonishment.toml), [Least Privilege](principles/least-privilege.toml), [Observability](principles/observability.toml), [Parameterize, Do Not Enumerate](principles/parameterize-do-not-enumerate.toml), [Psychological Acceptability](principles/psychological-acceptability.toml), [Separate Mechanism from Policy](principles/mechanism-policy-separation.toml) -- **architecture**: [Acyclic Dependencies Principle](principles/acyclic-dependencies.toml), [Complete Mediation](principles/complete-mediation.toml), [Conway's Law](principles/conways-law.toml), [Economy of Mechanism](principles/economy-of-mechanism.toml), [Fail-Safe Defaults](principles/fail-safe-defaults.toml), [High Cohesion, Low Coupling](principles/high-cohesion-low-coupling.toml), [Information Hiding](principles/information-hiding.toml), [Least Astonishment](principles/least-astonishment.toml), [Least Common Mechanism](principles/least-common-mechanism.toml), [Make Illegal States Unrepresentable](principles/make-illegal-states-unrepresentable.toml), [Optimize for Reversible Decisions](principles/reversible-decisions.toml), [Parameterize, Do Not Enumerate](principles/parameterize-do-not-enumerate.toml), [Reuse Maintained Components](principles/reuse-maintained-components.toml), [Rule of Least Power](principles/least-power.toml), [Rule of Three](principles/rule-of-three.toml), [Separate Mechanism from Policy](principles/mechanism-policy-separation.toml), [Separation of Concerns](principles/separation-of-concerns.toml), [Single Authoritative Source](principles/single-authoritative-source.toml), [Unix Composability](principles/unix-composability.toml) +- **architecture**: [Acyclic Dependencies Principle](principles/acyclic-dependencies.toml), [Complete Mediation](principles/complete-mediation.toml), [Conway's Law](principles/conways-law.toml), [Current Stack](principles/current-stack.toml), [Economy of Mechanism](principles/economy-of-mechanism.toml), [Fail-Safe Defaults](principles/fail-safe-defaults.toml), [High Cohesion, Low Coupling](principles/high-cohesion-low-coupling.toml), [Information Hiding](principles/information-hiding.toml), [Least Astonishment](principles/least-astonishment.toml), [Least Common Mechanism](principles/least-common-mechanism.toml), [Make Illegal States Unrepresentable](principles/make-illegal-states-unrepresentable.toml), [Optimize for Reversible Decisions](principles/reversible-decisions.toml), [Parameterize, Do Not Enumerate](principles/parameterize-do-not-enumerate.toml), [Reuse Maintained Components](principles/reuse-maintained-components.toml), [Rule of Least Power](principles/least-power.toml), [Rule of Three](principles/rule-of-three.toml), [Separate Mechanism from Policy](principles/mechanism-policy-separation.toml), [Separation of Concerns](principles/separation-of-concerns.toml), [Single Authoritative Source](principles/single-authoritative-source.toml), [Unix Composability](principles/unix-composability.toml) - **data**: [Explicit Unknown](principles/explicit-unknown.toml), [Reproducible Derived State](principles/reproducible-derived-state.toml), [Single Authoritative Source](principles/single-authoritative-source.toml) - **distributed-systems**: [Backpressure](principles/backpressure.toml), [End-to-End Principle](principles/end-to-end-principle.toml), [Graceful Degradation](principles/graceful-degradation.toml), [Idempotency](principles/idempotency.toml), [Robustness Principle](principles/robustness-principle.toml) -- **evolution**: [Chesterton's Fence](principles/chestertons-fence.toml), [Deprecation Discipline](principles/deprecation-discipline.toml), [Hyrum's Law](principles/hyrums-law.toml), [Namespaced Identifiers](principles/namespaced-identifiers.toml), [Optimize for Reversible Decisions](principles/reversible-decisions.toml), [Reproducible Derived State](principles/reproducible-derived-state.toml), [Reuse Maintained Components](principles/reuse-maintained-components.toml), [Rule of Three](principles/rule-of-three.toml) +- **evolution**: [Chesterton's Fence](principles/chestertons-fence.toml), [Current Stack](principles/current-stack.toml), [Deprecation Discipline](principles/deprecation-discipline.toml), [Hyrum's Law](principles/hyrums-law.toml), [Namespaced Identifiers](principles/namespaced-identifiers.toml), [Optimize for Reversible Decisions](principles/reversible-decisions.toml), [Reproducible Derived State](principles/reproducible-derived-state.toml), [Reuse Maintained Components](principles/reuse-maintained-components.toml), [Rule of Three](principles/rule-of-three.toml) - **interfaces**: [Deprecation Discipline](principles/deprecation-discipline.toml), [Fail Fast and Explicitly](principles/fail-fast.toml), [Follow Published Standards](principles/follow-published-standards.toml), [Hyrum's Law](principles/hyrums-law.toml), [Idempotency](principles/idempotency.toml), [Information Hiding](principles/information-hiding.toml), [Least Astonishment](principles/least-astonishment.toml), [Make Illegal States Unrepresentable](principles/make-illegal-states-unrepresentable.toml), [Namespaced Identifiers](principles/namespaced-identifiers.toml), [Parameterize, Do Not Enumerate](principles/parameterize-do-not-enumerate.toml), [Robustness Principle](principles/robustness-principle.toml), [Rule of Least Power](principles/least-power.toml), [Unix Composability](principles/unix-composability.toml) - **performance**: [Backpressure](principles/backpressure.toml) - **reliability**: [Backpressure](principles/backpressure.toml), [Defense in Depth](principles/defense-in-depth.toml), [End-to-End Principle](principles/end-to-end-principle.toml), [Enforcement Needs a Trigger](principles/enforcement-needs-a-trigger.toml), [Explicit Unknown](principles/explicit-unknown.toml), [Fail Fast and Explicitly](principles/fail-fast.toml), [Fail-Safe Defaults](principles/fail-safe-defaults.toml), [Graceful Degradation](principles/graceful-degradation.toml), [Host-Owned Logs](principles/host-owned-logs.toml), [Observability](principles/observability.toml), [Reproducible Derived State](principles/reproducible-derived-state.toml) @@ -78,9 +79,9 @@ Generated from `principles/*.toml`. Do not edit this file directly. ## By rung -- **text**: [Data Minimization](principles/data-minimization.toml), [Deprecation Discipline](principles/deprecation-discipline.toml), [Follow Published Standards](principles/follow-published-standards.toml), [Host-Owned Logs](principles/host-owned-logs.toml), [Minimize Attack Surface](principles/minimize-attack-surface.toml), [Namespaced Identifiers](principles/namespaced-identifiers.toml), [Reproducible Derived State](principles/reproducible-derived-state.toml), [Reuse Maintained Components](principles/reuse-maintained-components.toml) +- **text**: [Current Stack](principles/current-stack.toml), [Data Minimization](principles/data-minimization.toml), [Deprecation Discipline](principles/deprecation-discipline.toml), [Follow Published Standards](principles/follow-published-standards.toml), [Host-Owned Logs](principles/host-owned-logs.toml), [Minimize Attack Surface](principles/minimize-attack-surface.toml), [Namespaced Identifiers](principles/namespaced-identifiers.toml), [Reproducible Derived State](principles/reproducible-derived-state.toml), [Reuse Maintained Components](principles/reuse-maintained-components.toml) - **syntax**: [Chesterton's Fence](principles/chestertons-fence.toml), [Follow Published Standards](principles/follow-published-standards.toml), [Host-Owned Logs](principles/host-owned-logs.toml), [Reuse Maintained Components](principles/reuse-maintained-components.toml) -- **semantic**: [Acyclic Dependencies Principle](principles/acyclic-dependencies.toml), [Make Illegal States Unrepresentable](principles/make-illegal-states-unrepresentable.toml) +- **semantic**: [Acyclic Dependencies Principle](principles/acyclic-dependencies.toml), [Current Stack](principles/current-stack.toml), [Make Illegal States Unrepresentable](principles/make-illegal-states-unrepresentable.toml) - **none stated**: [Backpressure](principles/backpressure.toml), [Complete Mediation](principles/complete-mediation.toml), [Compromise Recording](principles/compromise-recording.toml), [Confused Deputy](principles/confused-deputy.toml), [Conway's Law](principles/conways-law.toml), [Defense in Depth](principles/defense-in-depth.toml), [Economy of Mechanism](principles/economy-of-mechanism.toml), [End-to-End Principle](principles/end-to-end-principle.toml), [Enforcement Needs a Trigger](principles/enforcement-needs-a-trigger.toml), [Explicit Unknown](principles/explicit-unknown.toml), [Fail Fast and Explicitly](principles/fail-fast.toml), [Fail-Safe Defaults](principles/fail-safe-defaults.toml), [Goodhart's Law](principles/goodharts-law.toml), [Graceful Degradation](principles/graceful-degradation.toml), [High Cohesion, Low Coupling](principles/high-cohesion-low-coupling.toml), [Hyrum's Law](principles/hyrums-law.toml), [Idempotency](principles/idempotency.toml), [Information Hiding](principles/information-hiding.toml), [Informed Consent for Consequential Actions](principles/informed-consent.toml), [Least Astonishment](principles/least-astonishment.toml), [Least Common Mechanism](principles/least-common-mechanism.toml), [Least Privilege](principles/least-privilege.toml), [Observability](principles/observability.toml), [Optimize for Reversible Decisions](principles/reversible-decisions.toml), [Parameterize, Do Not Enumerate](principles/parameterize-do-not-enumerate.toml), [Psychological Acceptability](principles/psychological-acceptability.toml), [Robustness Principle](principles/robustness-principle.toml), [Rule of Least Power](principles/least-power.toml), [Rule of Three](principles/rule-of-three.toml), [Separate Mechanism from Policy](principles/mechanism-policy-separation.toml), [Separation of Concerns](principles/separation-of-concerns.toml), [Separation of Privilege](principles/separation-of-privilege.toml), [Single Authoritative Source](principles/single-authoritative-source.toml), [Unix Composability](principles/unix-composability.toml) ## Alias index @@ -106,6 +107,7 @@ Machine-readable, and without this table's escaping, in [`name-index.json`](name | Canonical representation | [Single Authoritative Source](principles/single-authoritative-source.toml) | | Capability-based security | [Least Privilege](principles/least-privilege.toml) | | Check every access | [Complete Mediation](principles/complete-mediation.toml) | +| Choose what is current, not what is inherited | [Current Stack](principles/current-stack.toml) | | Cohesion and coupling | [High Cohesion, Low Coupling](principles/high-cohesion-low-coupling.toml) | | Collect only what is needed | [Data Minimization](principles/data-minimization.toml) | | Combinatorial explosion | [Parameterize, Do Not Enumerate](principles/parameterize-do-not-enumerate.toml) | @@ -123,6 +125,7 @@ Machine-readable, and without this table's escaping, in [`name-index.json`](name | Determinism | [Reproducible Derived State](principles/reproducible-derived-state.toml) | | Deterministic generation | [Reproducible Derived State](principles/reproducible-derived-state.toml) | | Distinguish not-violated from not-inspected | [Explicit Unknown](principles/explicit-unknown.toml) | +| Do not keep a choice because it was there | [Current Stack](principles/current-stack.toml) | | Do not reinvent the wheel | [Reuse Maintained Components](principles/reuse-maintained-components.toml) | | Do one thing well | [Unix Composability](principles/unix-composability.toml) | | Do what it says on the tin | [Least Astonishment](principles/least-astonishment.toml) | @@ -144,6 +147,7 @@ Machine-readable, and without this table's escaping, in [`name-index.json`](name | Human interface must not obstruct | [Psychological Acceptability](principles/psychological-acceptability.toml) | | Idempotent operation | [Idempotency](principles/idempotency.toml) | | Interface segregation | [High Cohesion, Low Coupling](principles/high-cohesion-low-coupling.toml) | +| Judge the stack afresh | [Current Stack](principles/current-stack.toml) | | Keep it simple | [Economy of Mechanism](principles/economy-of-mechanism.toml) | | Keep security simple | [Economy of Mechanism](principles/economy-of-mechanism.toml) | | KISS | [Economy of Mechanism](principles/economy-of-mechanism.toml) | diff --git a/REVIEW.md b/REVIEW.md index 4c4b484..1644f15 100644 --- a/REVIEW.md +++ b/REVIEW.md @@ -71,6 +71,21 @@ Any organization that designs a system will produce a design whose structure is - Did a recent reorganization change communication paths this design assumes? - Is a team change being proposed in order to reshape the architecture, and is that stated as its intent? +## Current Stack +Each choice of language, runtime, framework, library, toolchain, or service is made on today's evidence of fit and upkeep, and a choice carried forward from an earlier design needs a reason that holds now; that it was already in use is not one. + +**Applies when** +- A design or change picks a language, runtime, framework, library, toolchain, or hosted service, including by extending an existing one. +- The incumbent choice is chosen in the proposal because other parts already use it, not because of what it offers now. +- The incumbent is past its support window, is no longer maintained, or no longer receives security fixes. +- A newer option has a maintained release line and a migration path whose cost can be estimated. + +**Ask** +- Which language, runtime, framework, library, toolchain, or service does this design choose, and is each maintained today, judged by its release history, support window, and advisories? +- Where the choice is the one already in use, what current reason supports it other than that it was there? +- What would it cost to move to the alternative, and is that cost smaller or larger than the cost of staying put as the incumbent ages? +- Is the reason for the choice written where a later reader will find it, with the date it was judged? + ## Defense in Depth Protect critical assets and actions with multiple controls that fail differently and cover prevention, detection, containment, and recovery. diff --git a/name-index.json b/name-index.json index 085580f..9da3d8e 100644 --- a/name-index.json +++ b/name-index.json @@ -266,6 +266,24 @@ "title": "Chesterton's Fence", "path": "principles/chestertons-fence.toml" }, + { + "name": "Choose what is current, not what is inherited", + "key": "choose what is current not what is inherited", + "tokens": [ + "choose", + "what", + "is", + "current", + "not", + "what", + "is", + "inherited" + ], + "field": "alias", + "id": "current-stack", + "title": "Current Stack", + "path": "principles/current-stack.toml" + }, { "name": "Cohesion and coupling", "key": "cohesion and coupling", @@ -444,6 +462,18 @@ "title": "Conway's Law", "path": "principles/conways-law.toml" }, + { + "name": "Current Stack", + "key": "current stack", + "tokens": [ + "current", + "stack" + ], + "field": "title", + "id": "current-stack", + "title": "Current Stack", + "path": "principles/current-stack.toml" + }, { "name": "Data Minimization", "key": "data minimization", @@ -569,6 +599,25 @@ "title": "Explicit Unknown", "path": "principles/explicit-unknown.toml" }, + { + "name": "Do not keep a choice because it was there", + "key": "do not keep a choice because it was there", + "tokens": [ + "do", + "not", + "keep", + "a", + "choice", + "because", + "it", + "was", + "there" + ], + "field": "alias", + "id": "current-stack", + "title": "Current Stack", + "path": "principles/current-stack.toml" + }, { "name": "Do not reinvent the wheel", "key": "do not reinvent the wheel", @@ -1046,6 +1095,20 @@ "title": "High Cohesion, Low Coupling", "path": "principles/high-cohesion-low-coupling.toml" }, + { + "name": "Judge the stack afresh", + "key": "judge the stack afresh", + "tokens": [ + "judge", + "the", + "stack", + "afresh" + ], + "field": "alias", + "id": "current-stack", + "title": "Current Stack", + "path": "principles/current-stack.toml" + }, { "name": "Keep it simple", "key": "keep it simple", diff --git a/policy/upheld.toml b/policy/upheld.toml index 0d93809..1d2c4a8 100644 --- a/policy/upheld.toml +++ b/policy/upheld.toml @@ -265,6 +265,11 @@ record = "conways-law" catches = "Move principles/ and scripts/validate.py into a separate repository run by the people who write records, and have the Rust crate fetch it at a pinned revision, on the ground that record authors and engine maintainers rarely talk, although nearly every record-field change also edits src/catalog.rs and the schema in the same pull request." misses = "Add a CODEOWNERS entry that names the people who write records as reviewers for principles/, leaving the directory and the build in this repository." +[[review.control]] +record = "current-stack" +catches = "Pin rust-toolchain.toml `channel` to a release line the Rust project no longer supports, with the comment \"kept because every contributor already has it installed\" as the only reason, so the toolchain is retained for being there and not for any support it has today." +misses = "Raise rust-toolchain.toml `channel` from `stable` to an explicit current release number, with a comment saying the number is the supported line on the date the pin was written." + [[review.control]] record = "defense-in-depth" catches = "Delete the \"The policy over its own tree\" step from the scan engine job in .github/workflows/test.yml because the uphold-scan command in hooks/lefthook.yml already runs `uphold scan` on every commit, so a commit made with --no-verify is no longer scanned anywhere." diff --git a/principles/chestertons-fence.toml b/principles/chestertons-fence.toml index 9317d82..df47f92 100644 --- a/principles/chestertons-fence.toml +++ b/principles/chestertons-fence.toml @@ -13,7 +13,7 @@ does_not_mean = ["Keep everything whose purpose nobody can recover; after a boun benefits = ["Latent protections are not removed by accident.", "Removals leave evidence of intent in history.", "Unwritten knowledge is surfaced and written down at the moment it is needed."] costs = ["Cleanup slows while purposes are researched.", "Some purposes are unrecoverable, and the search has no natural end.", "Obsolete code accumulates when every removal must be justified at length."] failure_when_overapplied = ["Nothing is ever removed, and the system accumulates controls nobody understands and everyone is afraid to touch.", "The stated reason becomes a formula such as 'no longer needed' that satisfies the check while carrying no evidence.", "Removal waits on an author who has left, when a staged removal with monitoring would answer the question sooner.", "Only removals carry the burden, while additions without a stated purpose keep building new fences."] -conflicts_with = [] +conflicts_with = ["current-stack"] related = ["reversible-decisions", "observability", "hyrums-law", "deprecation-discipline"] review_questions = ["What did the removed thing prevent or provide, and where is that written?", "If its purpose could not be found, what was searched, and what would show that the removal was wrong?", "Is the purpose now served elsewhere, and does that place carry a test?", "Could a reader who meets the old failure again find this removal from the history alone?"] diff --git a/principles/current-stack.toml b/principles/current-stack.toml new file mode 100644 index 0000000..2492293 --- /dev/null +++ b/principles/current-stack.toml @@ -0,0 +1,55 @@ +id = "current-stack" +title = "Current Stack" +aliases = ["Judge the stack afresh", "Choose what is current, not what is inherited", "Do not keep a choice because it was there"] +kind = "principle" +status = "seed" +domains = ["architecture", "evolution"] +summary = "When a design picks a language, runtime, framework, library, toolchain, or service, pick what is current and maintained today, judged afresh against the need; do not keep a choice only because it was already there." +claim = "Each choice of language, runtime, framework, library, toolchain, or service is made on today's evidence of fit and upkeep, and a choice carried forward from an earlier design needs a reason that holds now; that it was already in use is not one." +problem = "A stack is inherited and then extended. The runtime is past its support window, the framework's maintainers have moved on, the toolchain is two majors behind, and each new component is chosen to match the old ones. Nobody decided to rely on any of it; the choice was made once, in a different year, and every later design copied it." +rationale = "A choice is evidence about the options available when it was made, and the options, the maintenance of each, and the project's needs have changed since. People weigh the existing option more heavily than an equal alternative, and weigh what is already spent on it as a reason to stay, so left alone the default drifts toward the inherited stack whatever its merits. Asking the question afresh at each design turns the inheritance into a candidate that has to win on current evidence, beside the others." +applies_when = ["A design or change picks a language, runtime, framework, library, toolchain, or hosted service, including by extending an existing one.", "The incumbent choice is chosen in the proposal because other parts already use it, not because of what it offers now.", "The incumbent is past its support window, is no longer maintained, or no longer receives security fixes.", "A newer option has a maintained release line and a migration path whose cost can be estimated."] +does_not_mean = ["Adopt the newest release or the newest tool; current means maintained and in use by its community today, and a version released last week has no such record.", "Rewrite working code to follow fashion; the incumbent keeps its place when it is still maintained and still fits, and the record says so.", "Remove what exists without finding out why it is there; the purpose of an inherited guard or choice is learned before it is dropped.", "Treat an inherited choice as a fault; judged afresh, it often wins, and then it is chosen and not merely kept.", "Choose several stacks, one per component; every new kind of technology has a cost in people who can run it, and a choice made afresh counts that cost."] +benefits = ["Choices rest on present evidence of support and fit, so end-of-life components are found at design time and not in an incident.", "Security fixes and platform support arrive from upstream instead of being carried locally.", "The reasons for a stack are written down where a later reader can test them."] +costs = ["Every design repeats an evaluation that inheriting would have skipped.", "Moving to a different option costs migration work, and the new option's pitfalls are not yet known to the team.", "A stack of mixed vintage is harder to operate than a uniform old one until the move finishes."] +failure_when_overapplied = ["The stack changes with each design, and no component lives long enough for anyone to learn it.", "Novelty is mistaken for currency, and an unproven tool replaces a maintained one.", "Migrations are started for components that are maintained and fit, consuming the effort the product needed.", "The judgment is repeated so often that decisions are never closed, and every review reopens the language."] +conflicts_with = ["chestertons-fence"] +related = ["reuse-maintained-components", "deprecation-discipline", "reversible-decisions", "follow-published-standards"] +review_questions = ["Which language, runtime, framework, library, toolchain, or service does this design choose, and is each maintained today, judged by its release history, support window, and advisories?", "Where the choice is the one already in use, what current reason supports it other than that it was there?", "What would it cost to move to the alternative, and is that cost smaller or larger than the cost of staying put as the incumbent ages?", "Is the reason for the choice written where a later reader will find it, with the date it was judged?"] + +[enforcement] +level = "review" +automatable = "partially" +rung = ["text", "semantic"] +observable = ["Versions of runtimes, toolchains, and dependencies in manifests and lock files, and the support status the publisher gives each release.", "Dependencies and runtimes that the publisher marks end-of-life or that carry an open advisory.", "A design or change description that names the stack choices it makes and the reason for each."] +checks = ["Flag a runtime, toolchain, or dependency whose release the publisher lists as past its support window, naming the supported release line.", "Report a dependency that has received no release in a stated period and whose repository is marked archived.", "Require a change that adds a component to state, beside it, why this component was chosen, and refuse an empty reason."] +limits = ["Whether an option fits the need is a judgment, and a version number says nothing about it.", "A support window is the publisher's claim, and a tool reads the published date, not whether the community still maintains the project.", "A tool cannot tell a choice judged afresh from an old choice with a new sentence beside it."] + +[[tools]] +name = "endoflife.date" +url = "https://endoflife.date/" +notes = "Publishes release and end-of-life dates for runtimes, frameworks, and operating systems, with an API; one way to observe whether a pinned version is still supported." + +[[sources]] +title = "Status Quo Bias in Decision Making" +url = "https://doi.org/10.1007/BF00055564" +type = "paper" +notes = "Samuelson and Zeckhauser, Journal of Risk and Uncertainty 1(1), 1988. Experiments and field data showing that decision makers favour the status quo option out of proportion to its merits; the drift this record's rationale names." + +[[sources]] +title = "The Psychology of Sunk Cost" +url = "https://doi.org/10.1016/0749-5978(85)90049-4" +type = "paper" +notes = "Arkes and Blumer, Organizational Behavior and Human Decision Processes 35(1), 1985. Prior investment makes people continue a course they would not now choose; the reason an inherited stack is not a reason for the next design." + +[[sources]] +title = "Choose Boring Technology" +url = "https://boringtechnology.club/" +type = "essay" +notes = "McKinley, 2015. The counterweight this record's does_not_mean carries: a team has a limited budget for new technology, and each new kind of component has a cost beyond its features." + +[[sources]] +title = "OWASP Top 10:2021 A06 Vulnerable and Outdated Components" +url = "https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/" +type = "documentation" +notes = "Names unsupported, out-of-date, and unmaintained components as a security risk, and a missing process for keeping versions current as the cause." diff --git a/review-controls.json b/review-controls.json index 6ef7f59..7e691fc 100644 --- a/review-controls.json +++ b/review-controls.json @@ -15,6 +15,11 @@ "catches": "Move principles/ and scripts/validate.py into a separate repository run by the people who write records, and have the Rust crate fetch it at a pinned revision, on the ground that record authors and engine maintainers rarely talk, although nearly every record-field change also edits src/catalog.rs and the schema in the same pull request.", "misses": "Add a CODEOWNERS entry that names the people who write records as reviewers for principles/, leaving the directory and the build in this repository." }, + { + "record": "current-stack", + "catches": "Pin rust-toolchain.toml `channel` to a release line the Rust project no longer supports, with the comment \"kept because every contributor already has it installed\" as the only reason, so the toolchain is retained for being there and not for any support it has today.", + "misses": "Raise rust-toolchain.toml `channel` from `stable` to an explicit current release number, with a comment saying the number is the supported line on the date the pin was written." + }, { "record": "defense-in-depth", "catches": "Delete the \"The policy over its own tree\" step from the scan engine job in .github/workflows/test.yml because the uphold-scan command in hooks/lefthook.yml already runs `uphold scan` on every commit, so a commit made with --no-verify is no longer scanned anywhere.", diff --git a/src/catalog.rs b/src/catalog.rs index 6774ee4..00eaa95 100644 --- a/src/catalog.rs +++ b/src/catalog.rs @@ -57,6 +57,10 @@ const RECORDS: &[(&str, &str)] = &[ "conways-law", include_str!("../principles/conways-law.toml"), ), + ( + "current-stack", + include_str!("../principles/current-stack.toml"), + ), ( "data-minimization", include_str!("../principles/data-minimization.toml"),