Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
14 changes: 9 additions & 5 deletions QUICK_REFERENCE.md

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
63 changes: 63 additions & 0 deletions name-index.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
5 changes: 5 additions & 0 deletions policy/upheld.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
2 changes: 1 addition & 1 deletion principles/chestertons-fence.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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?"]

Expand Down
55 changes: 55 additions & 0 deletions principles/current-stack.toml
Original file line number Diff line number Diff line change
@@ -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."
5 changes: 5 additions & 0 deletions review-controls.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
4 changes: 4 additions & 0 deletions src/catalog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down