maintain: the product is now a running system
Maintenance sessions still follow the session protocol: STATE.md first, one task, state updated.
Maintenance is scope-bound too; "while maintaining" is not a license to rebuild.
Observability: you cannot maintain what you cannot see
First maintenance session: confirm the minimum exists, or create it and record it in
docs/operations/monitoring.md:
- Errors are captured somewhere a human looks (error tracking, log alerts, per stack).
- The critical flow has a heartbeat: you find out it broke before the user tells you.
- Failure of background jobs/integrations is visible, not silently swallowed. The studied
production system's worst bugs were invisible failures marked "done".
The maintenance loop (each session, in this order)
- Signals: errors, alerts, intake since last session. Triage bugs (fix + regression test)
from wishes (INTAKE.md →
scope).
- Dependencies: audit for known vulnerabilities (blocking; fix now), then routine updates
in small, verified batches: never a big-bang upgrade with feature work mixed in. On a
platform stack (the stack file's header declares a hosted platform) the audit has the same
job and different subjects: connectors and the permissions they carry, installed managed
solutions and store apps, plugins and custom code registered in the instance, and the
vendor's own release and deprecation notices. Those last ones move on the vendor's schedule
rather than yours, which is what makes a platform go stale while every project file sits
untouched. The installed design method is a dependency too, and the only one whose manifest is
Groundwork's own config: this is the only place its two recorded versions move. It has two
because its npm package is a launcher that downloads the method's content at install time, so
the package version fixes the launcher and its engine binary while the content arrives at
whatever the current release is. The consequence to work with: re-installing can change the
method even when nothing in this repo changed. So treat an install as a version bump every
time. Run
node checks/design-method.mjs --install, read which content landed, exercise one
interface change end to end, then record that number as contentVersion in the thirdParty
entry of checks/config.json. Until it is recorded, the enforcement line at the top of
node checks/check.mjs keeps reporting that the payload is not the verified one, which is the
whole point: the change cannot be prevented here, so it is made impossible to miss. Note the
move in STATE.md. Read the release notes for a rule that was dropped: decision 0020 credits
rules to that method, and one that disappears upstream comes back into a Groundwork file
rather than being forked there. A content jump across a major is its own unit of work,
verified like any other, never folded into a routine batch.
- Debt harvest:
grep -rn "defer:" --exclude-dir=.git . → reconcile with DEBT.md. Flag
markers whose upgrade trigger has fired, and no-trigger markers (those rot silently).
Paying debt is a proposed, owner-approved task like any other.
- Drift check:
node checks/check.mjs + spot-check that STATE.md, BRIEF and reality still
agree. Docs describing a system that no longer exists → fix + denylist.
- Success metrics: a read date in BRIEF's measurement plan that has passed gets read now,
and the number written next to its criterion in BRIEF, dated. Nothing due, nothing to do.
Measured below target is a finding for
scope, not a defect for debug: the capability
works, the value did not arrive.
Incidents
Something is broken for real users: fix first, understand fully, then improve. Open
docs/operations/incident-response.md alongside step 1: its notification clocks (AP,
NCSC-NL, ENISA) count from the moment of awareness, not from the fix.
- Stabilize (rollback per runbook is a fine fix). 2. Root cause: the actual one, not the
first plausible one. 3. Regression test. 4. Ten-line post-mortem in
docs/operations/:
what, impact, cause, fix, what now detects it earlier. No blame, no essay.
Periodic audit (quarterly, or before major phases)
One focused pass: security posture, compliance register still current (comply), the specs at
done read against the running product (a criterion the product no longer meets reopens its spec;
the record never outranks the code), retention honored while running (the oldest record per purpose sits inside its period, and the deletion
job actually ran), backup restore proven again (a restore you haven't run this quarter is a
rumor), unused code/deps (stack dead-code tooling), skill library still curated, STATE.md log
rotated.
The stack standards file ages the same way the compliance register does. Its header carries the
date those facts were last verified; when that date is more than a quarter old, or the stack has
shipped a major version since, re-verify the file against the vendor's live documentation and
re-stamp the header (stack owns how, and its rule that a stack fact from model memory is a
rumor with a cutoff). The major-version half fires on the news rather than on the calendar: a
release that deprecates what the standards file blesses is worth knowing about in the week it
lands, not in the quarter it lands.
Findings → INTAKE/DEBT with severity; fix nothing unasked.
End of life: retiring a product, an environment, or an integration
comply makes two promises that only come due here: the retention periods written in the
register's processing record, and deletion that is implemented rather than described. This is
where they are kept. Decommissioning is a proposed, owner-approved task like paying debt, never
a cleanup done in passing, and it is the one maintenance job whose evidence someone may ask for
years later.
- The data goes, per the record. Every purpose in
docs/compliance/REGISTER.md's
processing record names a retention period; at end of life each one is deleted, or exported
first to the destination the owner agreed. Backups, replicas and analytics copies hold the
same personal data and outlive the primary store, so name when they expire too - a deletion
proven only against the live database is a deletion visible only from the front.
- The access goes with it. Credentials, API tokens, service accounts, connectors, webhooks
and third-party processor accounts created for this product are revoked at their source, and
the processor agreements that covered them are ended. A key nobody revoked outlives the
product it belonged to and has no owner left to notice it.
- Say what happened, where the promise lived. Record per purpose what was deleted or
exported and on what date, in the register that carried the retention promise, and note the
retirement in STATE.md. An undocumented deletion and a forgotten one look identical
afterwards. ⚓
1---2name: maintain3description: maintain: the product is now a running system4---56# maintain: the product is now a running system78Maintenance sessions still follow the session protocol: STATE.md first, one task, state updated.9Maintenance is scope-bound too; "while maintaining" is not a license to rebuild.1011## Observability: you cannot maintain what you cannot see1213First maintenance session: confirm the minimum exists, or create it and record it in14`docs/operations/monitoring.md`:15- Errors are captured somewhere a human looks (error tracking, log alerts, per stack).16- The critical flow has a heartbeat: you find out it broke before the user tells you.17- Failure of background jobs/integrations is *visible*, not silently swallowed. The studied18 production system's worst bugs were invisible failures marked "done".1920## The maintenance loop (each session, in this order)21221. **Signals**: errors, alerts, intake since last session. Triage bugs (fix + regression test)23 from wishes (INTAKE.md → `scope`).242. **Dependencies**: audit for known vulnerabilities (blocking; fix now), then routine updates25 in small, verified batches: never a big-bang upgrade with feature work mixed in. On a26 platform stack (the stack file's header declares a hosted platform) the audit has the same27 job and different subjects: connectors and the permissions they carry, installed managed28 solutions and store apps, plugins and custom code registered in the instance, and the29 vendor's own release and deprecation notices. Those last ones move on the vendor's schedule30 rather than yours, which is what makes a platform go stale while every project file sits31 untouched. The installed design method is a dependency too, and the only one whose manifest is32 Groundwork's own config: **this is the only place its two recorded versions move.** It has two33 because its npm package is a launcher that downloads the method's content at install time, so34 the package version fixes the launcher and its engine binary while the content arrives at35 whatever the current release is. The consequence to work with: **re-installing can change the36 method even when nothing in this repo changed.** So treat an install as a version bump every37 time. Run `node checks/design-method.mjs --install`, read which content landed, exercise one38 interface change end to end, then record that number as `contentVersion` in the `thirdParty`39 entry of `checks/config.json`. Until it is recorded, the enforcement line at the top of40 `node checks/check.mjs` keeps reporting that the payload is not the verified one, which is the41 whole point: the change cannot be prevented here, so it is made impossible to miss. Note the42 move in STATE.md. Read the release notes for a rule that was dropped: decision 0020 credits43 rules to that method, and one that disappears upstream comes back into a Groundwork file44 rather than being forked there. A content jump across a major is its own unit of work,45 verified like any other, never folded into a routine batch.463. **Debt harvest**: `grep -rn "defer:" --exclude-dir=.git .` → reconcile with DEBT.md. Flag47 markers whose upgrade trigger has fired, and `no-trigger` markers (those rot silently).48 Paying debt is a proposed, owner-approved task like any other.494. **Drift check**: `node checks/check.mjs` + spot-check that STATE.md, BRIEF and reality still50 agree. Docs describing a system that no longer exists → fix + denylist.515. **Success metrics**: a read date in BRIEF's measurement plan that has passed gets read now,52 and the number written next to its criterion in BRIEF, dated. Nothing due, nothing to do.53 Measured below target is a finding for `scope`, not a defect for `debug`: the capability54 works, the value did not arrive.5556## Incidents5758Something is broken for real users: fix first, understand fully, *then* improve. Open59`docs/operations/incident-response.md` alongside step 1: its notification clocks (AP,60NCSC-NL, ENISA) count from the moment of awareness, not from the fix.611. Stabilize (rollback per runbook is a fine fix). 2. Root cause: the actual one, not the62first plausible one. 3. Regression test. 4. Ten-line post-mortem in `docs/operations/`:63what, impact, cause, fix, what now detects it earlier. No blame, no essay.6465## Periodic audit (quarterly, or before major phases)6667One focused pass: security posture, compliance register still current (`comply`), the specs at68`done` read against the running product (a criterion the product no longer meets reopens its spec;69the record never outranks the code), retention honored while running (the oldest record per purpose sits inside its period, and the deletion70job actually ran), backup restore proven again (a restore you haven't run this quarter is a71rumor), unused code/deps (stack dead-code tooling), skill library still curated, STATE.md log72rotated.7374The stack standards file ages the same way the compliance register does. Its header carries the75date those facts were last verified; when that date is more than a quarter old, or the stack has76shipped a major version since, re-verify the file against the vendor's live documentation and77re-stamp the header (`stack` owns how, and its rule that a stack fact from model memory is a78rumor with a cutoff). The major-version half fires on the news rather than on the calendar: a79release that deprecates what the standards file blesses is worth knowing about in the week it80lands, not in the quarter it lands.8182Findings → INTAKE/DEBT with severity; fix nothing unasked.8384## End of life: retiring a product, an environment, or an integration8586`comply` makes two promises that only come due here: the retention periods written in the87register's processing record, and deletion that is implemented rather than described. This is88where they are kept. Decommissioning is a proposed, owner-approved task like paying debt, never89a cleanup done in passing, and it is the one maintenance job whose evidence someone may ask for90years later.9192- **The data goes, per the record.** Every purpose in `docs/compliance/REGISTER.md`'s93 processing record names a retention period; at end of life each one is deleted, or exported94 first to the destination the owner agreed. Backups, replicas and analytics copies hold the95 same personal data and outlive the primary store, so name when they expire too - a deletion96 proven only against the live database is a deletion visible only from the front.97- **The access goes with it.** Credentials, API tokens, service accounts, connectors, webhooks98 and third-party processor accounts created for this product are revoked at their source, and99 the processor agreements that covered them are ended. A key nobody revoked outlives the100 product it belonged to and has no owner left to notice it.101- **Say what happened, where the promise lived.** Record per purpose what was deleted or102 exported and on what date, in the register that carried the retention promise, and note the103 retirement in STATE.md. An undocumented deletion and a forgotten one look identical104 afterwards. ⚓