{ "id": "contradiction-01-branch-update-workflow", "kind": "contradiction", "prompt": "Update the \"Branch Updates\" section of docs/CONTRIBUTING.md so it accurately describes this repo's current, correct workflow for bringing a feature branch up to date with main.", "fixture": { "files": { "docs/CONTRIBUTING.md": "# Contributing\n\n## Branch Updates\n\nWhen a feature branch needs to incorporate changes from main, merge main into your branch with `git merge origin/main --no-ff` and push a merge commit.\n" } }, "seed_learnings": [ { "type": "preference", "content": "Update feature branches by merging main in with `git merge origin/main --no-ff`, preserving a merge commit for every sync.", "confidence": 6, "tags": [ "git", "workflow" ], "superseded": true }, { "type": "preference", "content": "Decision reversed: update feature branches with `git rebase origin/main`, not merge --no-ff. Rebase keeps history linear; push with --force-with-lease afterward.", "confidence": 8, "tags": [ "git", "workflow" ], "supersedes_previous": true, "supersede_reason": "Team switched from merge-commits to a rebase-based workflow for linear history." } ], "full_context_facts": [ "When bringing a feature branch up to date with main, this repo requires `git rebase origin/main` and never `git merge --no-ff`; after rebasing, push with `git push --force-with-lease` so history stays linear.", "The monorepo is split into three independently deployable services -- api, worker, and web -- each living in its own package directory with a dedicated build target and test suite, so a change confined to the worker service never triggers an api or web redeploy and can be released on its own schedule.", "Continuous integration runs on every pull request and hard-blocks the merge button until the lint, type-check, unit-test, and production-build steps have all reported a green status, and a single red step keeps the branch unmergeable no matter how many approvals it has collected.", "The default branch is main, all day-to-day work happens on short-lived feature branches named with a type-slash-short-description convention such as feature/add-widget or fix/null-guard, and branches are deleted automatically once their pull request merges.", "Squash-merge is the only merge strategy enabled on the main branch, ordinary merge commits and rebase-merges are both disabled in the repository settings, so every pull request lands on main as exactly one commit whose message is taken from the pull request title.", "Database migrations live in the supabase/migrations directory, are named with a zero-padded numeric prefix such as 0007_add_widget.sql, and are applied strictly in filename order by the migration runner during every deploy so the numeric prefix doubles as the ordering key.", "Every migration must be written to be idempotent, leaning on CREATE TABLE IF NOT EXISTS, ADD COLUMN IF NOT EXISTS, and DROP ... IF EXISTS guards, because the runner may replay a migration after a partially failed deploy and a non-idempotent statement would abort the whole release.", "Primary keys are always uuid columns defaulting to gen_random_uuid(), integer auto-increment keys are prohibited across the schema, and this rule exists so identifiers can be generated on the client before a row is ever written without risking a collision.", "All timestamp columns use the timestamptz type and store their values in UTC, the application layer is solely responsible for converting to a viewer's local time zone at render time, and a bare timestamp-without-time-zone column is rejected by the schema linter.", "The api service reads its entire configuration from environment variables that are loaded exactly once into a frozen config object during process startup, and any code that reaches for the process environment directly outside that central module is flagged by a custom lint rule.", "Secrets such as database passwords and third-party keys are injected at runtime through the deploy platform's encrypted secret store, are never written to the repository or to any committed dotfile, and rotating one is a matter of updating the store and restarting the affected service.", "The staging environment redeploys automatically on every push to main so the newest merged code is always live there within a few minutes, whereas production is deliberately gated behind a manual promote button that a release owner presses after smoke-checking staging.", "Feature flags are stored in a dedicated flags table, evaluated per tenant on each request through a small in-memory cache that refreshes every thirty seconds, and every flag carries an owner and an expiry date so stale flags can be swept up in quarterly cleanups.", "The platform is multi-tenant, so every domain table carries a tenant_id column, all queries are automatically scoped to the requesting tenant by a shared query helper, and forgetting to filter by tenant is treated as a security defect rather than a mere bug.", "Row-level security is enabled on all tenant-scoped tables and enforced with both a USING clause for reads and a WITH CHECK clause for writes, so even a query that forgot its tenant filter cannot leak or mutate another tenant's rows.", "Unit tests live directly beside the code they cover using a .test suffix rather than in a separate top-level tests tree, the intent being that a reviewer sees the test and its subject in the same directory listing and notices immediately when new code arrives without coverage.", "Integration tests run against an ephemeral database that the harness provisions fresh, migrates from zero, and tears down for every suite, so no test can ever depend on state left behind by another and the suite can be run in parallel shards without cross-talk.", "The worker service pulls background jobs from a queue table that it polls every five seconds, claims a batch inside a transaction using SELECT ... FOR UPDATE SKIP LOCKED, and marks each job done or failed before releasing the lock so two workers never process the same job.", "Structured JSON logging is used across every service, each line carries a request_id, a tenant_id, and a level field, and the log linter rejects any plain-text or string-concatenated log statement so downstream log tooling can parse every line mechanically.", "Error responses from the api always follow a single consistent envelope containing a machine-readable code, a human-readable message, and the originating request_id, and internal exception details are logged server-side but never included in the body returned to the client.", "The web app is a single-page application built with the standard bundler, emitted as a set of fingerprinted static assets, and served from a CDN edge, so a deploy of the web tier is just an upload of new immutable files rather than a running server swap.", "All outbound HTTP calls from any service go through one shared client that applies a sensible default timeout, retries idempotent requests with exponential backoff and jitter, and surfaces a circuit-breaker error once a downstream dependency has failed enough times in a row.", "Rate limiting is applied at the api gateway before a request ever reaches a service handler, the limit is keyed on tenant and endpoint, and an over-limit request receives a 429 response with a retry-after header rather than being silently dropped.", "Code style is enforced entirely by the formatter running on a pre-commit hook and again in CI, there is no hand-maintained style guide to argue over, and unformatted code fails the build so formatting never becomes a review comment.", "Import paths use configured path aliases that map short prefixes onto their source directories so that deeply nested relative imports never appear, and the alias map is kept in a single config file that both the bundler and the type-checker read.", "Pull request titles must reference an issue number using the number-colon-description format, a commit-msg hook rejects any commit that does not match it, and this convention is what lets the changelog generator group merged work under its originating issue.", "Every new or changed api endpoint requires a matching entry in the generated api reference document before it can merge, CI checks that the reference has been regenerated and committed, and a drifted reference fails the build to keep the docs honest.", "The local seed script populates a single demo tenant with a realistic spread of sample items, users, and settings so that a developer who has just cloned the repository sees a working, populated application on first run rather than empty screens.", "Long-running queries are automatically logged together with their execution plan whenever they cross a two-hundred-millisecond threshold, and the weekly performance review triages that log so a newly slow query is caught before it becomes a customer-facing incident.", "Cache entries in the shared cache layer expire after fifteen minutes by default unless a caller explicitly requests a longer or shorter time-to-live, and every cache key is namespaced by tenant so one tenant's cached data can never be served to another.", "Each build produces a single versioned artifact tagged with the short commit hash, that exact artifact is the one promoted unchanged from staging to production, and nothing is ever rebuilt between environments so the bytes that were tested are the bytes that ship.", "Production deploys are gated on a green status check from the full test suite running against the merged commit itself, not merely against the pull request branch, because a clean branch can still break once it is combined with whatever else landed on main first.", "Database connection pooling is capped at twenty connections per service instance, the cap is deliberately conservative to stay under the database's own connection ceiling once every instance and the migration runner are counted, and exhaustion surfaces as a fast error rather than a hang.", "All monetary amounts are stored as integer counts of the smallest currency unit, floating-point money is banned everywhere in the schema and the code, and formatting to a decimal string with a currency symbol happens only at the very edge when rendering to a user.", "Soft deletes are implemented with a nullable deleted_at timestamptz column rather than by physically removing rows, every default query filters out soft-deleted rows through a shared scope, and a genuine hard delete is a separate, audited, rarely-used operation.", "Audit records are written to an append-only audit_log table for every write to a tenant-scoped table, capturing the actor, the action, the before and after snapshots, and the request_id, and nothing is ever updated or deleted from that table once written.", "The api validates every incoming request body against a declared schema before any handler logic runs, a validation failure short-circuits to a 422 response listing the offending fields, and handlers are therefore free to assume their inputs are already well-formed.", "List endpoints use cursor-based pagination with an opaque, signed cursor token rather than numeric offsets, so that paging stays stable and cheap even as rows are inserted or deleted underneath a client that is walking through a large result set.", "Background job failures are retried up to five times with exponential backoff, a job that still fails after its final attempt is moved to a dead-letter table with its last error attached, and an alert fires once the dead-letter table grows past a small threshold.", "The staging database is reset every night from an anonymized snapshot of production, so staging data stays realistic in shape and volume while personally identifying fields are scrubbed, and no real customer data ever lands in the staging environment.", "Every new service must be registered in the service registry file at the repository root, that single file is the source of truth the gateway, the deploy tooling, and the monitoring dashboards all read, and an unregistered service is simply invisible to the platform.", "Environment-specific overrides live in per-environment config files that are merged over a shared defaults file at load time, a key absent from an environment file falls through to the default, and this layering keeps the diff between environments small and reviewable.", "The health-check endpoint returns the running service version, its build commit, and a live database-connectivity probe, the orchestrator polls it before routing traffic to a freshly deployed instance, and an instance that fails the probe is never added to the load balancer.", "All enumerations are stored as text columns constrained by a check constraint listing the allowed values rather than as native database enum types, because extending a check constraint is a cheap migration whereas altering a native enum type is awkward and lock-prone.", "Foreign keys always declare an explicit on-delete behavior, usually restrict for references that must not dangle and cascade for rows that are meaningless without their parent, and the schema linter rejects any foreign key that leaves the behavior unspecified.", "Column names use snake_case throughout the schema, camelCase identifiers are rejected by the schema linter, and the typed client generator is what maps those snake_case columns onto the camelCase field names the application code actually reads.", "Every table carries created_at and updated_at columns of type timestamptz, created_at is set once on insert and updated_at is refreshed on every write, so the age and last-touch time of any row can be read directly without consulting a separate history table.", "The updated_at column is refreshed automatically by a single shared set_updated_at trigger function that every table attaches through a BEFORE UPDATE trigger, so application code never has to remember to bump the timestamp by hand and can never forget to.", "Indexes are created concurrently inside migrations so that adding an index to a large, live table does not take a write lock that would stall production traffic, at the cost of the migration taking longer and being unable to run inside a surrounding transaction.", "The api exposes operational metrics in the standard text exposition format on a dedicated port, the monitoring agent scrapes that endpoint every thirty seconds, and dashboards and alerts are built on those scraped series rather than on anything parsed out of logs.", "Documentation lives in the docs directory as plain markdown, is rendered and published to the internal wiki automatically on every merge to main, and treating docs as code in the same repository is what keeps a feature and its documentation landing in the same pull request.", "Test fixtures are defined as small factory functions that build objects with sensible defaults and accept overrides for the fields a given test cares about, rather than as large static data files, so a schema change updates one factory instead of dozens of frozen blobs.", "The linter forbids direct console logging anywhere in service code and requires the injected structured logger instead, because a stray console call bypasses the request context, the log-level filtering, and the JSON formatting that the rest of the pipeline depends on.", "Commit messages follow an issue-number-colon-summary convention that a commit-msg hook enforces locally and CI re-checks on the server, and this discipline is what allows tooling to link any commit back to the issue that motivated it long after the branch is gone.", "Any change that touches the database schema must regenerate the typed database client and commit the regenerated file in the same pull request, and CI fails the build when the committed client does not match what the current schema would produce, preventing silent type drift.", "The provisioning scripts that stand up a new environment are written to be idempotent and safe to re-run against an already-provisioned environment, so recovering from a half-finished setup is simply a matter of running the same script again rather than unpicking partial state.", "Load tests run on a weekly schedule against the staging environment, replaying a representative traffic mix at several multiples of current production volume, and their latency and error-rate results are posted to a performance dashboard the team reviews together.", "The api version is pinned in a request header, the gateway rejects any client that sends an unsupported or missing version with a clear error, and this explicit contract is what lets the backend evolve its response shapes without silently breaking older clients.", "Local development brings up the full container stack -- database, cache, api, worker, and web -- with a single make target, and the same compose definition is used in continuous integration so the environment a developer debugs in matches the one the tests run in.", "Nightly encrypted backups of the production database are taken and retained on a thirty-day rolling window, a monthly restore drill verifies that a backup can actually be rebuilt into a working database, and an untested backup is treated as no backup at all.", "The web app fetches its runtime configuration from a small config endpoint the api serves at boot rather than baking environment values into the bundle, so the same immutable static build can be promoted across staging and production without a rebuild.", "Blue-green deploys keep two identical production environments behind the load balancer, releases go out by warming the idle color and then flipping traffic to it in one atomic switch, and a bad release is rolled back by flipping the traffic pointer straight back rather than redeploying.", "Schema changes that drop or rename a column are rolled out in two phases across separate releases, first shipping code that no longer depends on the column and only later removing it, so a rollback of either release always leaves the running code and the live schema compatible.", "The api enforces optimistic concurrency on updates through a version column that must match the value the client last read, a mismatch returns a conflict response instead of silently overwriting, and clients are expected to refetch and retry rather than force a stale write through.", "Every service ships with a readiness probe distinct from its liveness probe, the readiness probe reports false while the service is still warming caches or running migrations so traffic is withheld until it is genuinely ready, while the liveness probe only trips on a truly wedged process.", "Background schedules are defined declaratively in a single cron manifest rather than scattered across services, each entry names the job, its schedule, and its owning service, and a scheduler reads that manifest so there is exactly one place to see everything that runs on a timer.", "Distributed tracing is enabled across every service, each inbound request is assigned a trace id that is propagated through outgoing calls in a standard header, and a single trace can be followed end to end through the api, the worker, and the database layer in the tracing UI.", "Every public api route is declared in a single routing manifest that pairs the path with its handler, its required scopes, and its rate-limit bucket, so an auditor can read the full surface area of the service from one file rather than by grepping the codebase.", "Authentication uses short-lived signed access tokens paired with longer-lived refresh tokens, the access token is verified locally on each request without a database round trip, and revocation is achieved by rotating the signing key rather than by maintaining a denylist.", "Authorization is checked with a central policy function that takes the actor, the action, and the target resource and returns an allow or deny with a reason, and it is the only place in the codebase permitted to make an access decision so the rules cannot drift between call sites.", "Every list query has a hard maximum page size that the server clamps to even when a client asks for more, protecting the database from an unbounded scan that a careless or hostile caller might otherwise trigger against a very large table.", "The highest-volume event tables are partitioned by month, old partitions are detached and archived to cold storage on a rolling schedule, and a query that omits a time bound is rejected so a scan never accidentally spans every partition at once.", "Read replicas serve reporting and analytics queries so that heavy aggregate scans never contend with the transactional write path, and the application routes a query to a replica or the primary based on an explicit read-your-writes flag rather than by guessing.", "Every environment variable the application reads is declared in a single typed schema that is validated at startup, and a missing or malformed variable crashes the process immediately with a clear message rather than surfacing as a confusing failure deep inside a later request.", "Dependency upgrades are proposed automatically by a bot that opens one pull request per dependency, the change only merges once the full test suite is green, and a major-version bump is always split into its own reviewable pull request rather than batched with patch updates.", "The lockfile is committed and treated as authoritative, continuous integration installs strictly from it with no resolution step, and a pull request that changes a dependency without updating the lockfile fails the build so the two can never drift apart.", "Every service defines an explicit set of performance budgets, such as a p95 latency ceiling per endpoint, and a load-test run that breaches a budget fails the pipeline so a latency regression is caught before it ever reaches production traffic.", "Frontend bundles are code-split per route so the initial download contains only what the landing view needs, and a size-budget check fails the build if any route's bundle grows beyond the byte ceiling the team has agreed to.", "All user-facing strings live in translation catalogs keyed by a stable identifier rather than being hard-coded in components, and a linter flags any literal string rendered to the user that has not been routed through the translation layer.", "Accessibility checks run in the pipeline against every rendered page, common violations such as missing labels or insufficient contrast fail the build, and a deeper manual audit is scheduled before any major release ships to users.", "Third-party integrations are wrapped behind a narrow internal interface so that swapping one provider for another touches a single adapter module, and no service is ever allowed to import a vendor SDK directly outside that one adapter.", "Webhooks received from external systems are verified against a shared signature before any processing, are recorded in an inbound-events table for replay, and are handled idempotently so a duplicate delivery never causes a double effect.", "Outbound webhooks the platform sends are retried with exponential backoff on any non-success response, are signed so the receiver can verify them, and are disabled automatically for an endpoint that has failed continuously for a configured window.", "Every background job is designed to be idempotent so that the at-least-once delivery of the queue never causes duplicate side effects, and a job that cannot be made naturally idempotent must instead record a processed marker it checks on entry.", "The build pipeline is expressed as a single declarative workflow file checked into the repository, there are no hidden steps configured only in the CI dashboard, and a change to the pipeline goes through the same review as any code change.", "Container images are built from a pinned base image digest rather than a floating tag, are scanned for known vulnerabilities before they are pushed, and a critical finding blocks the release until the base image has been updated and rescanned.", "Each service declares its resource requests and limits explicitly so the scheduler can pack workloads predictably, and an out-of-memory kill is treated as a capacity bug to be investigated rather than as background noise to be ignored.", "Rollbacks are a first-class operation that redeploys the previously known-good artifact by its version tag in a single command, and every deploy records the artifact it replaced so the rollback target is never in doubt during an incident.", "Configuration changes are versioned and rolled out through the same review-and-deploy pipeline as code, so a change to a timeout or a feature threshold carries an audit trail and can be reverted exactly like a code change.", "Every alert that can page a human is required to link to a runbook describing the likely causes and first diagnostic steps, and an alert without a runbook is considered incomplete and is not allowed to reach the on-call rotation.", "Alert thresholds are tuned to fire on symptoms a user would notice, such as an elevated error rate or latency, rather than on internal causes, so that the on-call engineer is woken for real customer impact rather than for a transient internal blip.", "Every incident of customer impact is followed by a blameless written review capturing the timeline, the root cause, and concrete follow-up actions with named owners, and those follow-ups are tracked to completion like any other work.", "Data retention windows are defined per table and enforced by a scheduled job that deletes or anonymizes rows past their window, so personally identifying data is never retained for longer than the stated policy allows.", "Personally identifying fields are tagged in the schema so that exports, logs, and the anonymization job all know exactly which columns to redact, and a newly added such field is required to carry the tag in the same migration that introduces it.", "The test suite is tiered into fast unit tests that run on every save, a broader integration tier that runs in CI, and a slow end-to-end tier that runs before a release, so feedback stays quick locally while coverage stays thorough overall.", "End-to-end tests drive the real user interface against a fully migrated ephemeral stack, assert on accessible roles and visible text rather than on brittle selectors, and are quarantined rather than deleted the moment one becomes flaky.", "Flaky tests are tracked by a job that reruns failures and flags any test that passes on retry, a persistently flaky test is quarantined out of the blocking suite, and its owner is expected to fix the underlying race rather than paper over it.", "Every timeout, retry count, and backoff schedule in the system is a named configuration value rather than a magic number buried in code, so an operator can tune the platform's behavior under load without shipping a new build.", "Breaking api changes only ever land under a new major version in the path, an old version is supported for a published deprecation window before it is retired, and clients are given clear migration notes well ahead of the cutoff.", "Every response carries cache-control headers appropriate to its content, immutable assets are served with a long max-age and a fingerprinted url, and a dynamic private response is marked no-store so an intermediary never serves it to another user.", "Idempotency keys are accepted on every state-changing api call so that a client that retries after a network timeout does not create a duplicate resource, and the server records the key and returns the original result on a repeat.", "Numeric primary keys are never exposed in public urls, an opaque external identifier is used instead so that resource counts and creation rates cannot be inferred by an outsider incrementing a value in the address bar.", "Every query the application issues is parameterized, string concatenation to build sql is banned and caught by a linter, and this discipline is the platform's primary defense against injection regardless of where the input originally came from.", "Uploaded files are validated for both their declared content type and their actual sniffed type, are stored under a generated name rather than the user's filename, and are served from a separate origin so a malicious upload cannot execute in the application's own context.", "Background workers scale horizontally by simply running more identical instances against the same queue, no worker holds unique in-memory state, and the instance count is driven by the observed queue depth rather than by a fixed hard-coded number.", "The primary database is fronted by a connection pooler so that a burst of short-lived connections from many instances is multiplexed onto a bounded set of real backend connections, protecting the database from connection exhaustion.", "Every scheduled job records its last successful run time, a monitor alerts when a job has not completed within its expected interval, and a silent scheduler failure is therefore caught early rather than discovered only when its output goes stale.", "Sensitive operations such as changing a password or a login email require a recent re-authentication, so that a briefly unattended session or a stolen token cannot be used to take over an account without the current credential.", "Rate limits are applied at multiple layers, a coarse one at the edge to absorb volumetric abuse and a finer per-actor one at the application, so that a single hostile client cannot exhaust the capacity that legitimate traffic depends on.", "Every table expected to grow without bound has an explicit archival or partitioning strategy defined before it ships, because retrofitting one onto a table that is already enormous is far more disruptive than designing it in from the start.", "Indexes are reviewed against actual query patterns each quarter, an unused index is dropped because it only slows writes, and a frequently scanned column that lacks one is flagged for it, keeping the index set aligned with real usage.", "The application emits a structured business event for each meaningful user action, these events feed the analytics pipeline through a dedicated stream, and product metrics are computed from that stream rather than by scraping the transactional tables.", "Feature work is guarded behind a flag from its very first commit so incomplete code can merge to main safely, the flag defaults off in production, and it is removed in a cleanup pull request once the feature has fully rolled out.", "Long-lived branches are avoided in favor of small, frequently merged pull requests behind flags, because a branch that lives for weeks accumulates painful conflicts and hides work from the rest of the team until it lands in one risky drop.", "Every pull request is expected to be small enough to review in a single sitting, a change that grows too large is split into a reviewable sequence, and a giant pull request is treated as a process smell rather than a heroic contribution.", "Code review requires at least one approval from someone other than the author, the review focuses on correctness, tests, and clarity rather than style, and formatting comments are out of scope because the formatter already owns them.", "Generated code such as the typed database client or the api client is committed and clearly marked as generated, and a continuous-integration check regenerates it to confirm the committed copy still matches its source of truth.", "The repository enforces a single source of truth for shared types so that the api server and its clients cannot disagree about a payload shape, and a change to a shared type ripples into a compile error everywhere it is used.", "Every environment, from a developer's laptop to production, runs the same container images and the same migrations and differs only in configuration, so that a bug is far less likely to be an artifact of environment drift.", "A timeout is set on every external call so that a slow dependency degrades gracefully into a handled error rather than tying up a request thread indefinitely and cascading into a much wider outage.", "Circuit breakers wrap calls to flaky dependencies, opening after a run of failures to fail fast and shed load, then probing periodically to close again once the dependency has recovered, so one sick service does not drag the rest down.", "Bulk operations are chunked and processed in bounded batches with checkpoints so a large job can resume after an interruption rather than restarting from the beginning, and so it never holds a single enormous transaction open.", "Every migration is reviewed for its lock footprint on large tables, an operation that would take a long exclusive lock is rewritten into an online-safe sequence, and a genuinely risky migration is scheduled into a low-traffic window deliberately.", "The platform keeps a changelog generated from merged pull request titles grouped by their referenced issues, so anyone can see what shipped in a given release without reading the raw commit history line by line.", "Secrets are rotated on a fixed schedule and immediately after any suspected exposure, the rotation is a routine automated procedure rather than a scramble, and the application tolerates an old and a new secret being valid during the overlap.", "Least-privilege credentials are issued per service so each service can reach only the resources it actually needs, and a broad shared credential is treated as a security defect to be split apart rather than a convenience to be preserved.", "The build fails on any new compiler or linter warning rather than letting warnings accumulate, because a warning that is tolerated once becomes background noise that hides the next genuinely important one.", "Every network boundary assumes the other side can fail, responses are validated rather than trusted, and a malformed payload from a dependency is handled as an expected condition rather than being allowed to crash a handler.", "Observability dashboards are defined as code alongside the services they watch, so a new service ships with its dashboards and alerts already in place rather than having them bolted on manually only after an incident reveals the gap.", "The platform prefers boring, well-understood technology on its core path and confines experiments to clearly bounded, low-risk areas, because operational familiarity during an incident is worth more than the marginal benefit of a novel tool.", "Every asynchronous message carries a schema version so a consumer can handle an older or newer shape gracefully, and a breaking change to a message format is rolled out by supporting both shapes until every consumer has been upgraded." ], "criteria": [ "The updated Branch Updates section recommends git rebase origin/main as the way to bring a feature branch up to date, not git merge --no-ff.", "The section does not present the old merge --no-ff approach as the current recommendation (it may be omitted entirely, or explicitly marked as a superseded/old approach)." ] }