From 8180ca639bd5c5f77d150aa78aceaf52af10e49c Mon Sep 17 00:00:00 2001 From: sadeeq6400 Date: Sat, 17 Oct 2026 19:54:15 +0100 Subject: [PATCH 1/2] docs: add end-of-life, support, compatibility, and data residency policies Add four lifecycle policies under Governance/policies/ covering how the project decides what it stops supporting and says so: - END_OF_LIFE.md: how a decision is made, the Active to End-of-life stage model with 90-day intervals, the five points every announcement must state, and migration guidance written before the Deprecated stage. - SUPPORT.md: channels, response expectations in business days per request type, a named out-of-scope list with a reason for each entry, and the rule that acknowledgement is not resolution. - COMPATIBILITY.md: supported versions verified against app.config.ts and package.json, window lengths per surface, and drop criteria that each require stated evidence rather than an assertion. - DATA_RESIDENCY.md: storage location per data category, transfer restrictions, and an exception process where a residency change is never internal-only. Existing governance stays authoritative where it already sets a rule: the Security Policy keeps the supported release lines, the OS Version Support Policy keeps the minimum versions and notice period, and the Deprecation Policy keeps removal criteria. Each new document states what is enforced by CI today and what is a human review. Closes #1493 Closes #1494 Closes #1495 Closes #1496 --- Governance/policies/COMPATIBILITY.md | 174 +++++++++++++++++++++++++ Governance/policies/DATA_RESIDENCY.md | 176 ++++++++++++++++++++++++++ Governance/policies/END_OF_LIFE.md | 175 +++++++++++++++++++++++++ Governance/policies/SUPPORT.md | 161 +++++++++++++++++++++++ 4 files changed, 686 insertions(+) create mode 100644 Governance/policies/COMPATIBILITY.md create mode 100644 Governance/policies/DATA_RESIDENCY.md create mode 100644 Governance/policies/END_OF_LIFE.md create mode 100644 Governance/policies/SUPPORT.md diff --git a/Governance/policies/COMPATIBILITY.md b/Governance/policies/COMPATIBILITY.md new file mode 100644 index 0000000..8c08d7b --- /dev/null +++ b/Governance/policies/COMPATIBILITY.md @@ -0,0 +1,174 @@ +# Compatibility and Support Window Policy + +## Purpose + +This policy defines which operating-system versions, device tiers, and runtime versions +TeachLink Mobile supports, how long each window lasts, and what evidence is required +before a version is dropped. A support window that is never shortened turns into +support for everything; one that is shortened without evidence becomes an abandonment. +This document fixes both ends of that trade. + +## Scope + +This policy covers the **versions the app is built to run on** and the **length of time +each is supported**. It covers: + +- iOS and Android OS versions; +- device tiers, which are defined in the [Device Support Policy](../domains/DEVICE_SUPPORT.md); +- the Expo SDK and React Native versions the app is built against; +- the Node and package-manager versions used for local development and CI; and +- browser support for the web export, where the web build is treated as a first-class + surface. + +It does not cover which **release lines** receive security fixes, which is the +[Security Policy](../SECURITY_POLICY.md#supported-versions), or the criteria for a +platform version reaching end of life, which is the +[OS Version Support Policy](../domains/OS_VERSION_SUPPORT.md). This policy sets the +window; those two decide what happens inside and after it. + +## Supported Versions + +The authoritative current values, all verifiable from the repository: + +| Surface | Supported version | Source of truth | +| --- | --- | --- | +| iOS | 15.1 and later | Deployment target in `app.config.ts`, per the [OS Version Support Policy](../domains/OS_VERSION_SUPPORT.md) | +| Android | 7.0 (API level 24) and later | `minSdkVersion` in `app.config.ts` | +| Expo SDK | 54 | `expo` in `package.json` (`~54.0.33`) | +| React Native | 0.81 | `react-native` in `package.json` (`0.81.5`) | +| Node.js | The version used by CI, currently 20 | `.github/workflows/ci.yml` and `engines` in `package.json` | +| Web browsers | The current and previous major versions of Chrome, Safari, Firefox, and Edge | Verified in the `maestro/` flows and manual web export checks | + +"Supported" means, concretely, all of the following: + +- the app installs and launches on it; +- defects affecting it are triaged and fixed under the + [Support Policy](SUPPORT.md); +- it is included in the release testing matrix in the + [Device Support Policy](../domains/DEVICE_SUPPORT.md); and +- it is inside the support window below. + +A version that launches but is not in the testing matrix is not "mostly supported". +It is unsupported and untested, which is stated rather than glossed. + +## Window Length + +| Surface | Support window | Rationale | +| --- | --- | --- | +| Current OS version and the version before it | Full support while the OS vendor ships security updates, and for at least **12 months** after adoption | Security support from the vendor is what determines whether the project can patch the underlying platform | +| An OS version adopted less than 12 months ago | Provisional support | The project may not yet have adoption data; the window is confirmed or shortened at the 12-month review | +| Current release line | Security fixes, per the [Security Policy](../SECURITY_POLICY.md) | The line users are told to update to | +| Previous release line | Security fixes only, for as long as the store's propagation requires | Store submission lead time, not preference | +| Expo SDK and React Native version | Adopted within the upstream support window, and no longer than the upstream's own end-of-support date | The project cannot patch a runtime that upstream has ended | +| Node.js version for contributors | Current and active LTS | Contributors should not be pinned to an unmaintained runtime | +| Web browsers | Current and previous major version | Balances coverage against the cost of testing more engines | + +Rules that qualify the windows: + +- **The upstream floor is absolute.** The project does not ship a build targeting an OS + below the Expo SDK floor, regardless of how many users remain there. A supported + version the toolchain cannot build is not supported. +- **A window is measured from adoption, not from announcement.** Adoption is the release + in which the version is first shipped, not the issue in which it was proposed. +- **Windows do not run in parallel indefinitely.** At most two OS major versions are + supported per platform at a time. +- **An adopted version is not withdrawn early.** Removing support inside the 12-month + window requires the drop criteria below to be met and a documented exception. + +## Drop Criteria + +A version is dropped only when at least one criterion is met and the evidence is +recorded. Meeting a criterion starts the notice period; it does not drop the version on +the spot. + +| Criterion | Evidence required | +| --- | --- | +| The upstream runtime no longer supports it | The Expo SDK or React Native release in use states that the version is below its floor | +| The OS vendor has ended security updates | Vendor announcement, plus the version falling below 1 percent of sessions in the preceding 90 days | +| A required API is unavailable or blocked and no workaround exists | Documented attempt at the workaround, and confirmation that the platform team agrees no workaround exists | +| A critical vulnerability cannot be mitigated on the version | Security Officer determination that continued support creates unacceptable risk | +| A device tier fails the testing matrix irrecoverably | The [Device Support Policy](../domains/DEVICE_SUPPORT.md) matrix showing the failure, and a confirmed root cause in the platform rather than in the app | +| The store itself has withdrawn support | Store deprecation notice or minimum-version enforcement | + +Rules for dropping: + +- **Evidence is required, not asserted.** A claim of low usage is paired with the + session data and the period measured. Where the project has no usage data, the issue + states that and the criterion is treated as unmet. +- **Adoption data is measured over a stated period.** A percentage is accompanied by the + window it covers, so a momentary dip cannot drop a version. +- **The notice period still applies.** A drop meets the criteria, then waits the 90 days + the [Deprecation Policy](DEPRECATION.md#notice-period) requires, before removal takes + effect. A security-driven drop may shorten the period with a recorded exception, and + the [OS Version Support Policy](../domains/OS_VERSION_SUPPORT.md) describes that path. +- **Removal is a separate change.** Passing a criterion is not permission to delete the + support code in the same pull request that noticed the criterion. + +## Monitoring and Review + +| Activity | Cadence | Owner | +| --- | --- | --- | +| Confirm adoption data for the oldest supported version | Every 90 days | Maintainers | +| Confirm the upstream SDK floor has not moved | Every 90 days | Mobile platform maintainers | +| Review the window for each surface | Every 12 months | [Release Manager](../roles/RELEASE_MANAGER.md) | +| Verify the declared versions still match the repository | Every 12 months | Mobile platform maintainers | + +The version table above is verified against `app.config.ts` and `package.json` at each +review, and corrected in the same pull request if it has drifted. A compatibility policy +that states a version the build does not target is worse than one that states nothing. + +## Change Control + +Raising a minimum version, lowering one, or changing a window is a change with +consequences for users, so: + +- it is proposed in a pull request touching only the `Governance/` folder, for the + policy change itself; +- the removal of support for a version is a separate, code-affecting change following + the [Deprecation Policy](DEPRECATION.md) and the + [OS Version Support Policy](../domains/OS_VERSION_SUPPORT.md); +- both are referenced from the same tracking issue, so the policy and the code move + together rather than diverging. + +## Exceptions + +A window length that cannot be met for a documented reason — a vendor delay, an upstream +release that arrives without the promised support, a store policy that forces a +shorter window — is recorded in the +[Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) with the reason, +the compensating control, an approver holding the authority to grant it, and an expiry +no more than 12 months ahead. + +## Enforcement Status + +- Support levels are enforced by the release testing matrix in the + [Device Support Policy](../domains/DEVICE_SUPPORT.md) and by the Maestro flows in + `maestro/`, which are real and run in CI. Whether the current matrix covers every + version named above is verified by maintainers rather than by an automated check. +- CI runs on a fixed Node version from the workflow definition, so the developer-runtime + requirement is enforced for CI but not for local machines. +- No automation monitors OS adoption share or detects an upstream SDK floor change. The + 90-day monitoring activities above are human. + +## Ownership and Review + +The mobile platform maintainers own this policy with the +[Release Manager](../roles/RELEASE_MANAGER.md). It is reviewed when the project adopts +an Expo SDK or React Native release, at each 12-month review, and whenever a drop +criterion is met. Changes are proposed in a pull request that touches only the +`Governance/` folder. + +## Related Documentation + +- [OS Version Support Policy](../domains/OS_VERSION_SUPPORT.md): minimum versions, drop + criteria, and notice period +- [Device Support Policy](../domains/DEVICE_SUPPORT.md): device tiers and the testing + matrix +- [Security Policy](../SECURITY_POLICY.md): which release lines receive fixes +- [Deprecation Policy](DEPRECATION.md) and + [Deprecation Register](../registers/DEPRECATION_REGISTER.md) +- [End-of-Life Policy](END_OF_LIFE.md) and + [Support Policy](SUPPORT.md) +- [Versioning Policy](VERSIONING.md) and + [Release Manager role](../roles/RELEASE_MANAGER.md) +- [Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) diff --git a/Governance/policies/DATA_RESIDENCY.md b/Governance/policies/DATA_RESIDENCY.md new file mode 100644 index 0000000..d9bbb88 --- /dev/null +++ b/Governance/policies/DATA_RESIDENCY.md @@ -0,0 +1,176 @@ +# Data Residency Policy + +## Purpose + +This policy defines where TeachLink Mobile's data may be stored, which transfers are +permitted, and how a request to store it elsewhere is approved. Residency decisions are +made once and are hard to reverse: moving a store, changing a backup region, or adding a +processor in another jurisdiction commits the project to that choice, and data about +children carries consequences beyond the engineering. + +## Scope + +This policy covers the storage location of every category of data the app processes, +including: + +- account and authentication data, such as tokens and profiles; +- student, teacher, and school records; +- lesson content and offline cache data, per the + [Offline Data Governance](../domains/OFFLINE_DATA.md); +- telemetry, crash reports, and analytics events; +- push notification tokens and message content; +- in-app purchase and billing records held by the stores; +- backups, replicas, and disaster-recovery copies; and +- data processed by third parties on the project's behalf, including the AI and + analytics services in the [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md). + +It does not define what data is collected or on what basis, which is the +[Privacy Manifest Policy](../domains/PRIVACY_MANIFEST.md) and the +[Consent Management Policy](CONSENT_MANAGEMENT.md); how long data is kept, which is the +[Record Retention and Legal Hold Policy](RECORD_RETENTION.md); or the terms with a +processor, which are the [DPA Template](../compliance/DPA_TEMPLATE.md). + +## Principle + +Personal data is stored and processed in its **declared primary region**, and is not +transferred outside that region except where this policy permits it and the +[Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md) records it. + +The region is declared, not implied. A system with no stated region is treated as having +no approved region, and the default answer is that new storage in it is not approved +until the register says otherwise. + +## Storage by Data Category + +The table records where each category may be stored. Where the project operates no +infrastructure of its own, the region is the one operated by the named provider, which +is why the provider is named rather than a region label alone. + +| Data category | Primary storage | Region | Notes | +| --- | --- | --- | --- | +| Account and authentication data | Primary application database | As declared in the [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md) | Backups in the same region | +| Student, teacher, and school records | Primary application database | Same region as account data | Not replicated across regions | +| Lesson content and media | Object storage | Same region as the database | Replicated within region only | +| Push notification tokens | Push delivery provider | Provider's region, as declared in the [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md) | Tokens only; message content is not retained by the push provider beyond delivery | +| Crash reports and diagnostics | Crash reporting provider | Provider's region | Must not contain personal data, per the [Mobile Telemetry Governance](../domains/MOBILE_TELEMETRY.md) | +| Product analytics | Analytics provider | Provider's region | Pseudonymised identifiers only | +| Backups and disaster recovery | Backup storage | Same region as the primary store | Backups are not a loophole: a backup may not be used to relocate data | +| Offline cache on device | User's device | The user's device | Deleted with the app or by the user; see the [Right-to-Erasure Policy](DATA_DELETION.md) | +| Store billing records | App Store and Play Store | The store's region | Held by the platform; the project receives limited metadata | + +Two rules hold for every row: + +- **A category's primary store and its backups, replicas, and disaster-recovery copies + stay in the same region.** Separating them for durability does not change residency. +- **Where the project does not operate the infrastructure, the provider's region is the + project's region for that category**, and a provider changing regions is a + [subprocessor change](../registers/SUBPROCESSOR_REGISTER.md#change-notification-process) + requiring notice before it takes effect. + +## Transfer Restrictions + +A cross-border transfer is restricted, and each transfer must be justified in one of +three ways. + +| Transfer type | Permitted | Conditions | +| --- | --- | --- | +| Data processed by a processor located outside the region | **Yes, with conditions** | The processor is in the [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md); a DPA is in place per the [DPA Template](../compliance/DPA_TEMPLATE.md); the transfer mechanism is recorded; and users are told in the privacy policy | +| Data replicated to a backup or DR region outside the primary | **Only by exception** | Approved under the exception process below, with the region, the volume, and the duration recorded, and a plan to return it | +| Data transferred to a country the project's legal basis cannot reach | **No** | Not permitted by any exception. Where a transfer is legally prohibited, the feature or the provider is replaced rather than the transfer approved | +| Data moved between the project's own regions for availability | **Only with notice and a stated purpose** | Recorded in the register, and the purpose stated to users where it affects them | + +Rules that apply to every transfer: + +- **Transfer is a decision, not a side effect.** A provider that replicates data + globally by default is a transfer, and requires the same approval as a deliberate one. +- **The transfer mechanism is recorded.** The mechanism used for each transfer — such as + standard contractual clauses — is named in the register, so a change in mechanism is + visible. +- **Telemetry is not exempt.** Crash reports and analytics that leave the region are + transfers. They are acceptable only because they carry no personal data, which is a + condition of the [Mobile Telemetry Governance](../domains/MOBILE_TELEMETRY.md) rather + than a waiver of this policy. +- **Data on a user's device is under that user's control** and is not a residency + question for the project, though its handling is governed by the + [Encryption Policy](ENCRYPTION.md). + +## Exception Process + +An exception is required for any new storage location, region, or transfer not already +recorded as permitted above. + +1. **Open a request.** The request states the region, the data categories involved, the + provider, and the business reason the approved location is unavailable. +2. **Assess the risk.** The request describes what the change means for the people + whose data is involved, with particular attention to the + [Children's Data Policy](../compliance/CHILDRENS_DATA.md), since residency risk + differs sharply for data about children. +3. **Name the controls.** Every request names compensating controls: encryption in + transit and at rest per the [Encryption Policy](ENCRYPTION.md), restricted processor + access, a defined deletion path, and whether the transfer is visible to users in the + privacy policy. +4. **Propose an expiry.** An exception has an expiry date, no more than 12 months ahead. + A request without one is refused rather than granted conditionally. +5. **Approve.** The [Security Officer](../roles/SECURITY_OFFICER.md) and a maintainer + approve, since residency affects both security and the published privacy position. + Where the project has access to legal counsel, the request is put to them, and if + they did not review it the record says so rather than implying they did. +6. **Record.** The exception is entered in the + [Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md), and the + affected rows are added to the [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md) + with the region and the transfer mechanism. +7. **Tell users.** Where the exception changes what the privacy policy says, the policy + change is published before the change takes effect, following the + [Privacy Policy Governance](../compliance/PRIVACY_POLICY_GOVERNANCE.md). A residency + change is never internal-only. +8. **Review before expiry.** The approver is reminded ahead of the expiry date, and the + exception is closed or re-approved with fresh justification. + +Where the project's legal obligations in a given jurisdiction make the approved location +unavailable, the answer is to change the feature or the provider, not to store the data +anyway and record an exception. + +## Enforcement Status + +- Residency is a property of infrastructure configuration, not of application code, and + the project operates no database itself. This policy therefore governs the provider + choices recorded in the [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md) + and the [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md). +- No automated check verifies that a provider's region has not changed. Provider + region changes are caught through the subprocessor review, which is a human activity + on a stated cadence. +- Where a future backend is operated by the project, a region check in deployment + configuration would be the natural enforcement point, introduced under the + [Bot and Automation Governance Policy](BOT_AUTOMATION.md). + +## Exceptions + +Any deviation from the storage table or the transfer restrictions is recorded in the +[Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) through the process +above, with an approver holding the authority to grant it and an expiry no more than 12 +months ahead. + +## Ownership and Review + +The [Security Officer](../roles/SECURITY_OFFICER.md) owns this policy with the +[Release Manager](../roles/RELEASE_MANAGER.md), and the +[Community Manager](../roles/COMMUNITY_MANAGER.md) owns what the privacy policy says +about it. It is reviewed whenever a subprocessor or a provider changes, when a new data +category is added, when a legal requirement changes, and at least once every 12 months. +Changes are proposed in a pull request that touches only the `Governance/` folder. + +## Related Documentation + +- [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md): category, + region, and transfer mechanism +- [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md): every third party and + its change-notification period +- [DPA Template](../compliance/DPA_TEMPLATE.md): processor terms +- [Privacy Manifest Policy](../domains/PRIVACY_MANIFEST.md): what is collected +- [Privacy Policy Governance](../compliance/PRIVACY_POLICY_GOVERNANCE.md): what users + are told +- [Record Retention and Legal Hold Policy](RECORD_RETENTION.md): how long data is kept +- [Right-to-Erasure Policy](DATA_DELETION.md): how a user's data is deleted +- [Encryption Policy](ENCRYPTION.md): protection in transit and at rest +- [Children's Data Policy](../compliance/CHILDRENS_DATA.md): the heightened standard +- [Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) diff --git a/Governance/policies/END_OF_LIFE.md b/Governance/policies/END_OF_LIFE.md new file mode 100644 index 0000000..33f2e8e --- /dev/null +++ b/Governance/policies/END_OF_LIFE.md @@ -0,0 +1,175 @@ +# End-of-Life Policy + +## Purpose + +This policy defines how the project decides that a release line, a feature, a platform +version, or an integration has reached its end of life, how that decision is announced, +and what happens to the people still relying on it. End of life is a decision with +consequences for users, so it is made deliberately, with notice, and with a migration +path rather than by letting something lapse. + +## Scope + +This policy covers end of life for anything the project stops maintaining: + +- **Release lines**, following the two-line support window in the + [Security Policy](../SECURITY_POLICY.md#supported-versions); +- **Features and capabilities** removed from the app; +- **Platform and OS versions** no longer supported, following the + [OS Version Support Policy](../domains/OS_VERSION_SUPPORT.md); +- **Integrations and API surfaces** the backend no longer serves; and +- **Governance documents and processes** that are retired. + +It covers the decision, the announcement, and the transition. The day-to-day support +commitment made to users on a supported line is in the +[Support Policy](SUPPORT.md), and the rules that determine which versions are in scope +are in the [Compatibility and Support Window Policy](COMPATIBILITY.md). + +## How End of Life Is Decided + +End of life is a maintainer decision recorded in writing, not an automatic consequence +of a date passing. + +| Trigger | Decision | Approver | +| --- | --- | --- | +| A release line falls outside the supported window | Automatic, following the [Security Policy](../SECURITY_POLICY.md#supported-versions) | [Release Manager](../roles/RELEASE_MANAGER.md) confirms | +| A feature's purpose is gone, or its maintenance cost exceeds its use | Proposed in an issue with usage evidence | Maintainers, by [lazy consensus](processes/LAZY_CONSENSUS.md) | +| A dependency, OS, or platform can no longer be supported safely | Proposed in an issue citing the constraint | Maintainers, with the [Security Officer](../roles/SECURITY_OFFICER.md) | +| The project itself winds down | Proposed as a formal proposal | [Supermajority](SUPERMAJORITY.md), per the [Decision Rights Matrix](../matrices/DECISION_RIGHTS_MATRIX.md) | + +Rules that shape the decision: + +- **Evidence over instinct.** A feature is proposed for end of life with evidence of + low use or high cost. Where the project has no usage data, the issue says so + explicitly rather than asserting that a feature is unused. +- **Security is a reason, not a shortcut.** A security-driven end of life may use a + shorter notice, following the [Deprecation Policy](DEPRECATION.md#notice-period), but + it is still announced and still has a migration path. +- **No end of life by silence.** Something is not end of life because nobody has + mentioned it for a year. If it is still shipped, it is still maintained, or it is + brought to a decision explicitly. +- **A decision is reversible until it is announced.** Before announcement, a proposal + can be withdrawn without ceremony. After announcement, reversing it means a new + decision and a new announcement. + +## Support Reduction Stages + +End of life is a transition with stages, so that users and integrators get warning +before the capability disappears. + +| Stage | What it means | Duration before the next stage | What the project does | +| --- | --- | --- | --- | +| **Active** | Fully maintained: fixes, security updates, and new work as planned | — | Normal development | +| **Maintenance** | Receives security and critical fixes only; no new features | At least 90 days | Defects still triaged; [support](SUPPORT.md) continues | +| **Deprecated** | Announced as ending, replacement named, no new work | At least **90 days** of notice, per the [Deprecation Policy](DEPRECATION.md) | Migration guidance published; in-app or release-note notice | +| **Frozen** | No further changes of any kind; exists only for existing users | At least 90 days before removal | Remains installed and working; only a security fix that cannot wait may change it | +| **End of life** | No support, no fixes, no updates | Indefinite | Removed from distribution; existing installs stop receiving updates | + +Rules that apply across the stages: + +- A stage may not be skipped. Frozen follows Deprecated, and Deprecated follows + Maintenance, with the notice above, unless a documented emergency exception applies. +- Stage changes are recorded in the + [Deprecation Register](../registers/DEPRECATION_REGISTER.md) with the date, the + reason, and the approver. +- A user on a Frozen item is not left broken: if the platform or a provider removes + something the app depends on, that is a critical defect and is fixed under the + [Patch Management Policy](PATCH_MANAGEMENT.md) even during Frozen. +- Moving from Maintenance to Deprecated is the point at which users are asked to act. + Earlier stages do not require migration work from anyone. + +## Announcement + +An end-of-life decision is announced through every channel that reaches the people +affected, in the earliest applicable form: + +| Audience | Channel | +| --- | --- | +| Users of the app | Release notes, `CHANGELOG.md`, an in-app notice, and the store listing where the stage is user-visible | +| Integrators and downstream developers | A tracking issue, documentation, and the API deprecation notice | +| Maintainers | The [meeting cadence](../processes/MEETING_CADENCE.md) record and the release issue | +| Subprocessors affected by a change | Per the [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md#change-notification-process) notice period | + +Every announcement states the same five things: + +1. what is ending; +2. who is affected; +3. the date or version of the final stage; +4. the replacement or migration path; and +5. what support remains available, and until when. + +An announcement that does not include the migration path is incomplete. "We are +removing this" without "use this instead" transfers the whole cost of the decision to +the user. + +## Migration Guidance + +Migration guidance is written **before** the Deprecated stage begins, not alongside the +removal. + +- Each end-of-life item has a named replacement, or an explicit statement that there is + none and what users should do instead. +- For data, the guidance covers export and the retention position, per the + [Record Retention and Legal Hold Policy](RECORD_RETENTION.md), so a user is not told + to migrate data that will be deleted or to retain data they no longer have. +- For a platform or OS change, the guidance states the minimum supported version and + how to check it, following the + [OS Version Support Policy](../domains/OS_VERSION_SUPPORT.md). +- For an integration, the guidance states the replacement endpoint or the deprecation + date, and links the API documentation. +- The guidance is published in the documentation, not only in a release note, so it + remains findable after the announcement. + +## Turning It Off + +For a mobile app, end of life is enforced by the store rather than by the project. A +line that reaches end of life stops receiving updates from the store as well as from +the project, and new users are directed to the current version. Where the project's own +guidance differs from the store's enforcement, the project's guidance is corrected to +match reality rather than the reverse. + +The final act of end of life for a release line is recorded in the +[Deprecation Register](../registers/DEPRECATION_REGISTER.md) and reflected in the +[Security Policy](../SECURITY_POLICY.md) supported-versions table, so that the two +documents do not drift. + +## Exceptions + +A notice period shortened below 90 days requires a documented reason — typically a +security exposure or a provider withdrawal — an approver holding the authority to grant +it, and an entry in the +[Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) with an expiry no +more than 12 months ahead. Shortening the notice is permitted; skipping the +announcement is not. + +## Enforcement Status + +- The stage model is applied by maintainers when a deprecation is proposed. No + automation enforces the 90-day intervals or the ordering of the stages. +- Store-side enforcement of minimum versions is the platform's, not the project's, and + is outside the repository. +- The [Deprecation Register](../registers/DEPRECATION_REGISTER.md) is a maintained + document; its value depends on being updated when a stage changes. + +## Ownership and Review + +The Release Manager owns this policy with the maintainers. It is reviewed after every +end-of-life decision, when the support window changes, and at least once every 12 +months. Changes are proposed in a pull request that touches only the `Governance/` +folder. + +## Related Documentation + +- [Support Policy](SUPPORT.md): the support commitment during each stage +- [Compatibility and Support Window Policy](COMPATIBILITY.md): which versions are in + scope +- [Deprecation Policy](DEPRECATION.md): notice period and removal criteria +- [Deprecation Register](../registers/DEPRECATION_REGISTER.md): the record of each + deprecation and its stage +- [Security Policy](../SECURITY_POLICY.md): the supported release lines +- [OS Version Support Policy](../domains/OS_VERSION_SUPPORT.md): platform versions +- [Versioning Policy](VERSIONING.md): how versions and lines are numbered +- [Record Retention and Legal Hold Policy](RECORD_RETENTION.md): what happens to data + at end of life +- [Release Cadence](../processes/RELEASE_CADENCE.md) and + [Release Manager role](../roles/RELEASE_MANAGER.md) diff --git a/Governance/policies/SUPPORT.md b/Governance/policies/SUPPORT.md new file mode 100644 index 0000000..9001376 --- /dev/null +++ b/Governance/policies/SUPPORT.md @@ -0,0 +1,161 @@ +# Support Policy + +## Purpose + +This policy defines what support TeachLink Mobile offers, through which channels, +within what response expectations, and what is explicitly out of scope. Without a +written scope, every unanswered question becomes an implicit promise, and the +difference between "we will look at it" and "we will fix it" is decided by whoever +happens to read the issue. + +## Scope + +This policy covers support **requests** — questions and reports that arrive through a +support channel and need a response. It does not cover the underlying engineering +processes, which are governed elsewhere: + +| Concern | Owner | +| --- | --- | +| Security vulnerability reports | [Security Policy](../SECURITY_POLICY.md) | +| Code of Conduct concerns | [Code of Conduct Reporting](../COC_REPORTING.md) | +| Review turnaround on pull requests | [Code Review Service Level Agreement](REVIEW_SLA.md) | +| Security remediation deadlines | [Vulnerability Remediation SLA Policy](VULN_SLA.md) | +| Defect triage and prioritisation | [Issue Triage Process](../processes/TRIAGE.md) | +| Data subject requests, such as erasure | [Right-to-Erasure Policy](DATA_DELETION.md) | + +Where a request arrives in the wrong channel, it is redirected to the right one rather +than answered informally in the wrong place. A vulnerability report sent to a public +issue is treated as disclosed and is handled under the +[Security Policy](../SECURITY_POLICY.md) immediately, not after a public comment. + +## Support Channels + +| Channel | Use it for | Response expectation | +| --- | --- | --- | +| GitHub issues | Defect reports, feature requests, and questions that benefit from a public, searchable answer | Acknowledged within **5 business days**; see [Response Expectations](#response-expectations) | +| GitHub discussions | Open-ended questions, ideas, and use cases that are not defects | Acknowledged within **7 business days** | +| Security reporting channel | Anything security-sensitive, including a vulnerability in the app or the backend | Per the [Security Severity Rubric](../SECURITY_SEVERITY_RUBRIC.md#response-sla-per-level) | +| Code of Conduct reporting | Behaviour or conduct concerns | Per the [Code of Conduct Reporting](../COC_REPORTING.md) process | +| Documentation | Usage and contribution questions | No response; the documentation is the answer | + +Rules that apply to every channel: + +- **One question per issue.** A broad issue asking several unrelated things cannot be + tracked to closure. It is split, or answered with a pointer to the individual issues. +- **Search first, ask second.** The requester is asked to search existing issues, and + a duplicate is closed with a link to the original rather than answered twice. +- **Answer in public by default.** Anything about the app's behaviour is answered in the + issue, so the next person finds it. Personal data is not, and a request containing + personal data is redirected to a private channel before it is discussed. +- **Acknowledgement is not resolution.** Acknowledging a request promptly and then + leaving it silent for months is the failure mode this policy is designed to prevent. +- **No support by private message.** Maintainers are asked to redirect private requests + to a public channel, which protects both the requester and the maintainer. + +## Response Expectations + +Response expectations are stated in **business days**, Monday to Friday, excluding +public holidays in the project's primary time zone. + +| Request type | Acknowledgement | First substantive response | Update cadence if unresolved | +| --- | --- | --- | --- | +| Defect with a clear reproduction | 2 business days | 5 business days | Every 10 business days | +| Defect that cannot be reproduced from the description | 3 business days | Ask for the missing detail within 5 business days | Every 10 business days | +| Feature request | 5 business days | Triaged within 10 business days; no commitment to implement | Every 30 days until triaged | +| Question about behaviour or documentation | 3 business days | 5 business days | Every 10 business days | +| Security report | Per severity rubric | Per severity rubric | Per severity rubric | +| Code of Conduct report | Per the enforcement policy | Per the enforcement policy | Per the enforcement policy | +| Contributor blocked on an access or process question | 5 business days | 10 business days | Every 10 business days | + +What "acknowledgement" and "first substantive response" mean: + +- **Acknowledgement** confirms the request was seen, is in the right channel, and is + not already covered elsewhere. It does not promise a fix or a date. +- **First substantive response** gives the requester something actionable: triage + outcome and severity, the missing detail needed to proceed, a link to an existing + issue, or a decision not to pursue with the reason. +- **An update cadence is a promise to stay in contact.** A request that goes quiet is + worse than one that is declined, because the requester cannot plan around it. + +Nothing in this policy promises a fix. Whether a defect is fixed, and when, follows the +[Issue Triage Process](../processes/TRIAGE.md) and the +[Milestone Governance](../processes/MILESTONE_GOVERNANCE.md), and the answer is +communicated as soon as it exists. + +## Out of Scope + +The following are not support obligations, and saying so early is kinder than +disappointing someone later. + +| Out of scope | Why, and what to do instead | +| --- | --- | +| Guaranteeing a fix, a date, or inclusion in a release | Work is prioritised through triage and milestone governance. Ask for it as a feature request, which is tracked | +| Support for an end-of-life release line or OS version | Out of the support window per the [Compatibility and Support Window Policy](COMPATIBILITY.md). Update to a supported version | +| Support for modified, repackaged, or unofficial builds | Not produced or verified by the project, and signing is covered by the [App Signing Key Policy](../domains/APP_SIGNING_KEYS.md) | +| Third-party services, hardware, or other apps | Point the requester to that provider; where it affects the app, a defect report with the integration details is welcome | +| Customisation, white-labeling, or feature development for one organisation | A request to a maintainer is not free capacity; see the project's scope in the [Scope Statement](../SCOPE.md) | +| Deployment, hosting, or backend operations for a self-hosted instance | Not something the project operates or supports; this is stated rather than discovered per request | +| Data recovery for content lost on a device the user no longer controls | Explained with the reason, per the [Offline Data Governance](../domains/OFFLINE_DATA.md) | +| Legal advice, and interpretation of data-protection law for a specific case | The project can point to the published [Privacy Policy Governance](../compliance/PRIVACY_POLICY_GOVERNANCE.md), not advise on a case | +| Assessment of a third party's security posture | Not in scope; reports about a dependency are welcome as a defect, per the [Vendor Risk Policy](VENDOR_RISK.md) | +| Feature requests that conflict with the [Non-Goals](../NON_GOALS.md) or the [Vision](../VISION.md) | Declined with a link to those documents, which is a decision rather than a deferral | + +An out-of-scope request is answered politely, with the reason and, where one exists, a +pointer to the right place. It is not dismissed without an answer. + +## Escalation + +A request that is not answered within its response expectation, or that the requester +believes was mishandled, escalates through the +[Escalation Path](../processes/ESCALATION_PATH.md). An unanswered accessibility barrier, +a request involving children's data, or a request from someone blocked by a language or +disability barrier escalates immediately rather than waiting for the full expectation +to lapse. + +Escalation of a security concern skips this policy entirely and goes straight to the +[Security Policy](../SECURITY_POLICY.md). + +## Data in Support Requests + +- A support request must not contain personal data about a student or child. If it + does, the requester is asked to remove it and it is not quoted in a public reply. + Concerns about children's data follow the + [Children's Data Policy](../compliance/CHILDRENS_DATA.md). +- A requester is asked not to include passwords, tokens, or keys, and any that arrive + are treated as exposed and rotated per the + [Secret Rotation Policy](SECRET_ROTATION.md). +- Logs or screenshots are shared through the channels the [Security Policy](../SECURITY_POLICY.md) + describes, not pasted into a public issue, when they may contain personal data. + +## Enforcement Status + +- Response expectations are a human commitment tracked by the + [Issue Triage Process](../processes/TRIAGE.md) and reviewed in the maintainer + review. No automation measures response times or warns about an ageing issue. +- The first-response timings are consistent with the + [Stale Issue Policy](STALE_ISSUES.md), which handles issues that receive no + maintainer attention. +- Enforcement is therefore by review and by the monthly report, not by a gate. + +## Ownership and Review + +The maintainers and the [Community Manager](../roles/COMMUNITY_MANAGER.md) own this +policy, with the [Issue Triager](../roles/TRIAGER.md) responsible for the triage +response. It is reviewed when a channel is added or removed, when the support model +changes, and at least once every 12 months. Changes are proposed in a pull request that +touches only the `Governance/` folder. + +## Related Documentation + +- [Issue Triage Process](../processes/TRIAGE.md): how a defect is prioritised +- [Code Review Service Level Agreement](REVIEW_SLA.md): reviewer and author + expectations on pull requests +- [Escalation Path](../processes/ESCALATION_PATH.md): what to do when a response + expectation is missed +- [Stale Issue Policy](STALE_ISSUES.md) and [Stale Pull Request Policy](STALE_PRS.md) +- [Security Policy](../SECURITY_POLICY.md) and + [Code of Conduct Reporting](../COC_REPORTING.md) +- [Compatibility and Support Window Policy](COMPATIBILITY.md) and + [End-of-Life Policy](END_OF_LIFE.md) +- [Contributor Onboarding Process](../processes/ONBOARDING.md) and + [Community Manager role](../roles/COMMUNITY_MANAGER.md) From a4d688a0d80856120b52f2637a136675989f0558 Mon Sep 17 00:00:00 2001 From: sadeeq6400 Date: Sat, 17 Oct 2026 20:12:33 +0100 Subject: [PATCH 2/2] docs(governance): fix relative link to the lazy consensus process The link omitted the ../ prefix, so it resolved to Governance/policies/processes/ rather than Governance/processes/. Closes #1493 --- Governance/policies/END_OF_LIFE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Governance/policies/END_OF_LIFE.md b/Governance/policies/END_OF_LIFE.md index 33f2e8e..5889066 100644 --- a/Governance/policies/END_OF_LIFE.md +++ b/Governance/policies/END_OF_LIFE.md @@ -33,7 +33,7 @@ of a date passing. | Trigger | Decision | Approver | | --- | --- | --- | | A release line falls outside the supported window | Automatic, following the [Security Policy](../SECURITY_POLICY.md#supported-versions) | [Release Manager](../roles/RELEASE_MANAGER.md) confirms | -| A feature's purpose is gone, or its maintenance cost exceeds its use | Proposed in an issue with usage evidence | Maintainers, by [lazy consensus](processes/LAZY_CONSENSUS.md) | +| A feature's purpose is gone, or its maintenance cost exceeds its use | Proposed in an issue with usage evidence | Maintainers, by [lazy consensus](../processes/LAZY_CONSENSUS.md) | | A dependency, OS, or platform can no longer be supported safely | Proposed in an issue citing the constraint | Maintainers, with the [Security Officer](../roles/SECURITY_OFFICER.md) | | The project itself winds down | Proposed as a formal proposal | [Supermajority](SUPERMAJORITY.md), per the [Decision Rights Matrix](../matrices/DECISION_RIGHTS_MATRIX.md) |