Appendix A: Code Examples: The Artefacts of the Twelve Steps
This appendix holds the complete versions of the artefacts that the twelve steps of Vibe to Dev produce, for the two builds that run through the book: service-point-check at Nordvik Region (builder Hanna Wikström) and claims-doc-check at Hansa Mutual (builder Katarzyna Nowak). Each section names the chapter that owns the artefact, says what the artefact is for and what it must never contain, and gives the Nordvik Region file and the Hansa Mutual file side by side in the same shape, so that a reader can copy the shape and replace the values.
Where a chapter prints an artefact in full, the file below is that file. Where a chapter prints an extract or only describes the artefact, the file below is completed from the technical facts of the two builds (docs/BUILDS.md) and from what the chapters state, and a comment in the file says composed. Where two chapters give different values for the same field, the file follows the earlier chapter and the difference is listed in the final section of this appendix. Every person, record, date and figure is fictional and illustrative. Every YAML block parses and every Python block compiles; the text of the appendix was checked that way before it was committed. Legal references are organisational and architectural implications, not legal advice. No artefact is attack tooling, and none holds personal data: the Hansa Mutual build uses synthetic claims (SYN-0001 onwards) in development, and its production export is read only by the identity of the group pipeline.
How to use this appendix
- Start with the build record (A.1, A.2). It is the one file that lists every gate, the artefact that met it, the date and the evidence. Every other artefact is a file that the record points to.
- Copy the shape, not the values. Dates, names, counts and limits are those of the two builds. Replace every one, and keep a field only if you can fill it with something that is true of your build.
- Keep the oracle outside the assistant. The verification plan (A.9), the review record (A.10) and the mandate (A.7) say who wrote the oracle cases and that the assistant cannot edit them. A plan without that line proves little.
- Date every piece of evidence. Each claim has a date and an expiry (
valid_until,expires). At Tier C the rule of the book is 90 days or the next change of code, dependency, rules or assistant, whichever comes first. - Lower at once, raise by decision. A mandate may lower a ceiling and never raise it. Level 4 Autonomous is not used for any action class of a builder's assistant.
- Check mechanically what can be checked (A.19). The short scripts there reject an intent that is incomplete, a tier that contradicts the answers, an ownership record that is overdue, a package that is not on the policy and a learning plan without a second assessor. They do not replace a person reading the artefact.
Identifier families
| Family | Artefact | Step | Owning chapter | Section |
|---|---|---|---|---|
BLD-NR-*, BLD-HM-* |
Build record: intent, tier, gates | all | 4, 5, 6 | A.1, A.2 |
SPC-NR-*, SPC-HM-* |
Specification record | 4 | 8 | A.3, A.4 |
DSG-* and ADR |
One-page design and Architecture Decision Record | 5 | 9 | A.5 |
AGENTS.md |
Project rules file for the assistant | 3 | 7 | A.6 |
MND-NR-BLD-*, MND-HM-BLD-* |
Builder mandate for the assistant | 3 | 4, 7 | A.7 |
RUN-NR-*, RUN-HM-* |
Agent run record | 6 | 10 | A.8 |
VER-NR-*, VER-HM-* |
Verification plan with the independent oracle | 7 | 11 | A.9 |
RVW-NR-*, RVW-HM-* |
Review record | 7 | 11 | A.10 |
PRV-NR-*, PRV-HM-* and the dependency policy |
Provenance record | 8 | 12 | A.11 |
pipeline.yml |
Pipeline definition | 9 | 13 | A.12 |
CHG-NR-*, CHG-HM-* and the rollback note |
Change record | 9 | 13 | A.13 |
RBK-*, RST-*, alerts |
Runbook manifest, restore-test record | 10 | 14 | A.14 |
OWN-NR-*, OWN-HM-* |
Code-ownership record | 11 | 15 | A.15 |
HND-* and TKT-* |
Handover pack and takeover-test result | 12 | 16 | A.16 |
BLP-*, CMP-* |
Builder learning plan and competence record | all | 21 | A.17 |
BREG-*, LANE-* |
Register entry and builder lane | 3, 9, 12 | 17 | A.18 |
| scripts | Gate and consistency checks | all | 5, 6, 12, 15, 21 | A.19 |
AIDR-1200 to AIDR-1299 |
AI Decision Records (Nordvik Region 1200 to 1249, Hansa Mutual 1250 to 1299) | 4 | referenced throughout |
Records used by the two builds: AIDR-1200 builder workspace (Nordvik Region, 2031-10-06); AIDR-1201 mandate MND-NR-BLD-2031-01 (2031-10-13); AIDR-1203 promotion of service-point-check to Tier C (2031-12-15); AIDR-1250 builder lane (Hansa Mutual, 2031-10-13); AIDR-1251 data protection screening (2031-10-20); AIDR-1252 mandate MND-HM-BLD-2031-01 (2031-10-27).
A.1 Build record: Nordvik Region
Owned by Chapters 4, 5 and 6; one record per build, kept in docs/build-record.yaml. The record carries the intent (Step 1), the tier decision (Step 2) and one entry per gate. It never holds a secret, a production value or personal data. The intent section is the full form of Chapter 5; the tier answers are those of the tier decision of 2031-12-15, which Chapter 6 reads with the classifier of A.19. The gate dates are those of the record in Chapter 4.
id: BLD-NR-2031-0001
name: service-point-check
repository: service-point-check
version: 0.2.0
opened: 2031-09-08
builder: Hanna Wikström
deputy: Elin Berg
manager: Gunilla Roos
intent:
purpose: >-
Report every week where the opening hours and service notices of the
24 service points differ between the citizen portal, the phone-service
script and the notices spreadsheet.
user: >-
The e-services team, who correct the sources, and the service-point
managers, who read the weekly report.
problem_now: >-
The three sources disagree after every change. Residents travel to a
service point that is closed and then phone the phone service.
success_measure:
what: Calls to the phone service categorised "wrong opening hours" per month
source: Phone-service call log, category count
baseline: {value: 41, period: 2031-08}
target: At most 20 a month in the first full month on a schedule
note: Before-and-after count of one category; no control group
done:
- One command compares all 24 service points, SP-01 to SP-24
- The report names every mismatch with the service point and the field
- The tool only reads; it never writes to any of the three sources
non_goals:
- Correcting the sources automatically
- The printed leaflet, which is produced from the portal export
- Opening hours of anything other than the 24 service points
affected:
- Service-point managers, whose figures are compared
- Phone-service agents, who answer the calls
- Residents, who rely on the published hours
open_questions:
- Who owns the notices spreadsheet after a manager leaves?
gate:
status: met
date: 2031-09-10
read_back_by: Elin Berg
approved_by: Gunilla Roos
review_by: 2031-12-09
tier:
current: C
answers: # as of the decision of 2031-12-15 (AIDR-1203)
users: units
data: internal
money: false
organisational_record: false
unattended: true
ranks_or_decides_about_a_named_person: false
feeds_a_high_risk_ai_system: false
security_critical_path: false
irreversible_on_production_data: false
history:
- {tier: B, decided: 2031-09-11, reclassify_if: [runs_on_schedule, used_by_other_units]}
- {tier: C, decided: 2031-12-15, decision: AIDR-1203}
mandate: MND-NR-BLD-2031-01
gates:
1_intent: {status: met, date: 2031-09-10, artefact: "intent (this record)", evidence: "read and confirmed by the phone-service lead and Gunilla Roos"}
2_tier: {status: met, date: 2031-09-11, artefact: "tier (this record)", evidence: "countersigned by Gunilla Roos; five questions answered"}
3_workshop: {status: met, date: 2031-10-13, artefact: "README, AGENTS.md, MND-NR-BLD-2031-01", evidence: "clone-and-restore test by Elin Berg: pass"}
4_specification: {status: met, date: 2031-10-15, artefact: SPC-NR-2031-0001, evidence: "approved; oracle owner Saga Edvardsson"}
5_design: {status: met, date: 2031-10-20, artefact: "docs/design.md, docs/adr/0001-0003", evidence: "read by Anders Falk"}
6_build: {status: met, date: 2031-11-05, artefact: "commits, docs/runs/RUN-NR-2031-*", evidence: "3 slices; tests pass from a fresh clone"}
7_prove: {status: met, date: 2031-11-05, artefact: "VER-NR-2031-0001, RVW-NR-2031-0001", evidence: "14 tests and 12 oracle cases pass; review by Anders Falk", expires: 2032-02-03}
8_secure: {status: met, date: 2031-11-06, artefact: PRV-NR-2031-0001, evidence: "tier B checklist complete; secret scan clean; one token in the secret store", expires: 2032-02-04}
9_ship: {status: met, date: 2031-12-12, artefact: "CHG-NR-2031-0001, CHG-NR-2031-0002, docs/rollback.md", evidence: "v0.1.0 on 2031-11-12; v0.2.0 on 2031-12-08; reopened 2031-12-11, rollback note named a tag; met 2031-12-12"}
10_run: {status: met, date: 2031-12-05, artefact: "RBK-NR-2031-0001, RST-NR-2031-0001", evidence: "restored from release on the template; output matched", expires: 2032-03-04}
11_own: {status: met, date: 2031-12-02, artefact: OWN-NR-2031-0001, evidence: "explain-it-back drill by Elin Berg without the assistant: pass; sunset 2033-08-31"}
12_hand_over: {status: met, date: 2031-12-12, artefact: "HND-NR-2031-0001, TKT-NR-2031-0001", evidence: "takeover test 2031-12-11 by Rasmus Holm: 9 of 10 items; T6 revert failed, fixed and re-run 2031-12-12: pass"}
next_evidence_expiry: 2032-02-03
A.2 Build record: Hansa Mutual
The same shape for claims-doc-check. Chapter 4 prints only the Nordvik Region record; this record is composed from the tier decision of Chapter 6, the specification of Chapter 8 and the dates of Chapters 11 to 16. The intent date and the people who read it back and approved it are composed (composed), because no chapter states them.
id: BLD-HM-2031-0001
name: claims-doc-check
repository: claims-doc-check
version: 0.1.0
opened: 2031-09-15
builder: Katarzyna Nowak
deputy: Marek Zieliński
manager: Joanna Kaczmarek
intent:
purpose: >-
For motor property-damage claims, list the documents still missing from
each claim file and draft a request text for the handler to review and send.
user: >-
The claims handlers of the pilot team in the Polish service centre.
problem_now: >-
Handlers check each claim file by hand for missing documents, so files
wait for days before the claimant is asked.
success_measure:
what: Median calendar days from claim registration to complete file, pilot team
source: Claims core, pilot team report
baseline: {value: 6.8, period: 2031-09, claims: 212}
target: Lower; no figure promised
note: Before-and-after without a control group; other changes in the period are not controlled
done:
- One job lists the missing documents for every claim in scope
- A draft request in the claim's language (pl, de or en) exists for every claim with missing documents
- The tool never decides a claim, never sends a message and never writes to the claims core
non_goals:
- Deciding or ranking claims, handlers or claimants
- Injury claims (motor_injury), whose free text may hold health data
- Sending any message to a claimant
affected:
- Claims handlers, who review and send the drafts
- Claimants, who receive the requests
open_questions: []
gate:
status: met
date: 2031-09-17 # composed; no chapter states the date
read_back_by: Marek Zieliński
approved_by: Joanna Kaczmarek
review_by: 2031-12-17
tier:
current: C
decided: 2031-09-18
answers:
users: team
data: personal
money: false
organisational_record: false
unattended: false
ranks_or_decides_about_a_named_person: false
feeds_a_high_risk_ai_system: false
security_critical_path: false
irreversible_on_production_data: false
reason: Claim identifiers are linkable to claimants; several handlers use it
screening: {by: "Dr. Sabine Vogel, group data protection officer", date: 2031-10-20, decision: AIDR-1251}
approved_by: Joanna Kaczmarek
review_by: 2031-12-17
mandate: MND-HM-BLD-2031-01
gates:
1_intent: {status: met, date: 2031-09-17, artefact: "intent (this record)", evidence: "read back by Marek Zieliński; approved by Joanna Kaczmarek"}
2_tier: {status: met, date: 2031-10-20, artefact: "tier (this record)", evidence: "Tier C decided 2031-09-18; gate met on the attachment of the screening by the data protection officer 2031-10-20 narrowed the scope (AIDR-1251)"}
3_workshop: {status: met, date: 2031-10-27, artefact: "README, AGENTS.md, MND-HM-BLD-2031-01", evidence: "clone-and-restore test by Marek Zieliński: pass; mandate adopted (AIDR-1252)"}
4_specification: {status: met, date: 2031-10-30, artefact: SPC-HM-2031-0001, evidence: "approved; oracle owner Marek Zieliński; quality sample from the head of claims operations' office"}
5_design: {status: met, date: 2031-11-03, artefact: "docs/design.md, docs/adr/0001-0002", evidence: "one-page design accepted: four modules, one input, two outputs, no network"}
6_build: {status: met, date: 2031-11-06, artefact: "commits, docs/runs/RUN-HM-2031-*", evidence: "3 slices; 18 tests pass from a fresh clone"}
7_prove: {status: met, date: 2031-11-12, artefact: "VER-HM-2031-0001, RVW-HM-2031-0001", evidence: "oracle case glass-03 failed on first run 2031-11-08; rules.yaml corrected 2031-11-10; 25 of 25 pass", expires: 2032-02-08}
8_secure: {status: met, date: 2031-11-13, artefact: PRV-HM-2031-0001, evidence: "logs hold claim ids and counts only; dependencies checked by Tomasz Wrona; secret scan clean", expires: 2032-02-11}
9_ship: {status: met, date: 2031-11-12, artefact: "CHG-HM-2031-0001", evidence: "rollback rehearsed by Marek Zieliński 2031-11-12, 12 minutes against 30; v0.1.0 to the pilot team 2031-11-17", expires: 2032-02-10}
10_run: {status: met, date: 2031-11-14, artefact: "RBK-HM-2031-0001, RST-HM-2031-0001", evidence: "rebuilt from the tag in 18 minutes against 30 by Marek Zieliński, assistant off", expires: 2032-02-12}
11_own: {status: met, date: 2031-12-03, artefact: OWN-HM-2031-0001, evidence: "explain-it-back drill by Marek Zieliński without the assistant: pass; sunset 2033-08-31"}
12_hand_over: {status: met, date: 2031-12-09, artefact: "HND-HM-2031-0001, TKT-HM-2031-0001", evidence: "takeover test 2031-12-09 by Tomasz Wrona: pass with two remarks, R2 open"}
next_evidence_expiry: 2032-02-08
A.3 Specification record: Nordvik Region
Owned by Chapter 8. The specification says what correct means, before the code does. Its oracle owner is neither the builder nor the assistant. It never holds a rule without an example, and the assistant may propose a change to it and may not adopt one. The file below joins the two extracts of Chapter 8 (rules and acceptance examples, then failure cases and never-do rules) into one record.
id: SPC-NR-2031-0001
title: service-point-check, weekly comparison of opening hours and notices
status: approved
date: 2031-10-15
build: BLD-NR-2031-0001
owner: Hanna Wikström # the builder; decides scope
oracle_owner: Saga Edvardsson # quality engineer; writes tests/oracle/cases.yaml
delegation: MND-NR-BLD-2031-01
need:
statement: >
The Region publishes the opening hours of its 24 service points in three
places that are updated by different people. Residents and phone-service
staff meet different answers.
evidence:
- source: phone-service count of calls categorised "wrong opening hours"
result: 41 in August 2031
read_by: Hanna Wikström
rules:
- id: R1
text: For each service point and weekday, the opening hours are equal in the portal export and the phone script.
- id: R2
text: A notice whose date range covers today appears in both the portal export and the phone script.
- id: R3
text: Every service point SP-01 to SP-24 is present in all three sources.
acceptance_examples:
- id: AC1
covers: R1
given: SP-07 has Monday hours "09:00-16:00" in the portal and "09:00-16:00" in the phone script
when: the comparison runs
then: there is no mismatch for SP-07 on Monday
- id: AC2
covers: R1
given: SP-07 has Friday hours "09:00-16:00" in the portal and "09:00-15:00" in the phone script
when: the comparison runs
then: there is exactly one mismatch, kind hours, service point SP-07, field fri, with both values shown
- id: AC3
covers: R2
given: >
notices.csv has a notice for SP-12 from 2031-12-22 to 2032-01-06, today is 2031-12-29,
the phone script shows the notice and the portal export does not
when: the comparison runs
then: there is exactly one mismatch, kind notice, service point SP-12, naming the portal as the source that lacks it
- id: AC4
covers: R3
given: SP-19 is present in the phone script and in notices.csv but not in the portal export
when: the comparison runs
then: there is exactly one mismatch, kind missing_service_point, service point SP-19, naming the portal
failure_cases:
- id: F1
given: a phone-script cell for SP-03 on Tuesday reads "9-16"
then: a mismatch of kind malformed_hours is reported for SP-03 and the comparison continues with the other service points
- id: F2
given: portal.json is not valid JSON
then: the run stops with a message that names the file and no report is written
- id: F3
given: SP-05 appears twice in phone.csv
then: a mismatch of kind duplicate_id is reported and the first row is used for the comparison
never_do:
- id: N1
text: Write to the portal, the phone script or the notices spreadsheet; the three sources are opened for reading only.
- id: N2
text: Report a service point as correct because one source is missing; a missing source is a mismatch.
out_of_scope:
- correcting the sources
- checking the hours themselves against the service points' doors
open_questions:
- question: Which notice text counts as equal when the portal and the phone script word it differently?
owner: Hanna Wikström
decision_needed_by: 2031-10-22
assumptions:
- Hours are written "HH:MM-HH:MM" or left empty for a closed day.
ai_involvement:
- tool: approved assistant of the builder workspace (Mode 2)
use: drafted the rule wording and proposed seven failure cases; Hanna kept three
reviewed_by: Hanna Wikström
tests:
AC1: pending
AC2: pending
AC3: pending
AC4: pending
review_due: 2032-01-15
A.4 Specification record: Hansa Mutual
The same shape for claims-doc-check. The glass example AC5 and the failure case F1 are not in Chapter 8: Chapter 11 states that the glass example was added to the specification after the oracle found the error of 2031-11-10, and the file below adds it in the form of the other examples (composed).
id: SPC-HM-2031-0001
title: claims-doc-check, missing documents in motor property-damage claim files
status: approved
date: 2031-10-30
build: BLD-HM-2031-0001
owner: Katarzyna Nowak
oracle_owner: Marek Zieliński # senior claims handler; did not write the checker
quality_sample: office of the head of claims operations, drawn without the assistant
delegation: MND-HM-BLD-2031-01
scope:
claim_types: [motor_collision, motor_parking_damage, motor_glass]
out_of_scope_types: [motor_injury] # free text may hold health data; recorded in AIDR-1251
rules:
- id: R1
text: A motor_collision claim needs photos, accident_report and repair_estimate.
- id: R2
text: A motor_parking_damage claim and a motor_glass claim each need photos and repair_estimate.
- id: R3
text: A claim of type motor_injury is written as OUT_OF_SCOPE and is not processed.
- id: R4
text: For each claim with missing documents a draft request is written in the claim's language (pl, de or en) for the handler to review and send.
acceptance_examples:
- id: AC1
covers: R1
given: claim SYN-0001, type motor_collision, documents received "photos;repair_estimate"
when: the check runs
then: status MISSING, missing "accident_report"
- id: AC2
covers: R2
given: claim SYN-0002, type motor_parking_damage, documents received "photos;repair_estimate"
when: the check runs
then: status COMPLETE and no draft is written
- id: AC3
covers: R3
given: claim SYN-0003, type motor_injury, documents received "photos"
when: the check runs
then: status OUT_OF_SCOPE, no documents are listed and no draft is written
- id: AC4
covers: R4
given: claim SYN-0004, type motor_collision, language pl, documents received "photos"
when: the check runs
then: a draft in Polish asks for exactly "accident_report" and "repair_estimate" and mentions no other document
- id: AC5 # added 2031-11-10 after oracle case glass-03 failed; composed in this form
covers: R2
given: claim SYN-0005, type motor_glass, documents received "photos;repair_estimate"
when: the check runs
then: status COMPLETE, and no accident report is asked for
never_do:
- Decide a claim, rank handlers or claimants, or say that a claim is valid or invalid.
- Send any message; the handler reviews and sends from the claims core.
- Write to the claims core or read a free-text field.
- Log anything but claim ids and counts.
A.5 One-page design and Architecture Decision Record
Owned by Chapter 9. The design is read by a developer or architect in ten minutes. It never holds a secret or a value for a production path. The Nordvik Region design record and its first decision record are as Chapter 9 prints them; the Hansa Mutual decision record states the decision of 2031-10-20 (AIDR-1251) as a design decision and is composed from Chapters 6, 8 and 16.
id: DSG-NR-2031-0001
build: BLD-NR-2031-0001
spec: SPC-NR-2031-0001
tier: B
reviewed_by: Anders Falk
date: 2031-10-20
purpose: Compare opening hours and notices for 24 service points in three sources.
stack:
language: Python 3.12
libraries: [PyYAML, pytest]
runs_on: platform scheduled-job template
output: wiki page Service point check
data:
reads: [portal.json, phone.csv, notices.csv]
writes: [wiki page only]
personal_data: none
secrets: [WIKI_TOKEN]
access:
tool_may: [read the three exports, write the wiki page]
tool_may_not: [write to the portal, the phone script or the notices sheet]
accessibility:
output_form: plain Markdown with headings and one table
language: Swedish for the report text
cost:
per_run: no extra cost on the existing scheduled-job template
exit: delete the repository; the wiki page keeps its last report
adr: ['0001', '0002', '0003']
docs/adr/0001-scheduled-job-template.md (Nordvik Region):
# 0001 Use the platform's scheduled-job template
Status: accepted (2031-10-20)
Decider: Hanna Wikström, with Anders Falk's team as reviewer
## Context
The tool must run weekly without Hanna starting it. The platform team already
runs a scheduled-job template for Python and monitors it.
## Decision
Run on the scheduled-job template. No new hosting.
## Consequences
The job is monitored and patched by the platform team. The tool must accept
its inputs as environment variables. We cannot use anything the template
does not allow.
## Assistant's part
The assistant proposed a small web service and a cloud function. Hanna
rejected both because nobody in the Region maintains them.
## Review
Review date: 2032-01-20
docs/adr/0001-property-damage-only.md (Hansa Mutual; composed):
# 0001 Limit the tool to motor property-damage claims
Status: accepted (2031-10-30)
Decider: Katarzyna Nowak, approved by Joanna Kaczmarek
Related: AIDR-1251, SPC-HM-2031-0001
## Context
The first draft of the scope included injury claims. The free-text fields of
injury claims may hold health data. The group data protection officer,
Dr. Sabine Vogel, screened the tool on 2031-10-20.
## Decision
The tool handles motor_collision, motor_parking_damage and motor_glass.
Claims of type motor_injury are written as OUT_OF_SCOPE and not processed.
The tool reads no free-text field.
## Consequences
No data protection impact assessment was required for the narrowed scope.
A new claim type or a free-text field needs a new screening before it is added.
## Assistant's part
The assistant drafted the wording of the scope; Katarzyna and the data
protection officer decided it.
## Review
Review date: 2031-12-17
A.6 Project rules file: AGENTS.md
Owned by Chapter 7. AGENTS.md is the file the assistant reads at the start of every session. It restates the mandate in plain sentences and never overrides it; where they differ, the mandate applies. It never holds a secret or a production path. The assistant may not edit it. The Nordvik Region file is as Chapter 7 prints it; the Hansa Mutual file is composed from the build facts.
# AGENTS.md: rules for the assistant in service-point-check
Build record BLD-NR-2031-0001. Mandate MND-NR-BLD-2031-01. Owner: Hanna Wikström.
These rules restate the mandate; where they differ, the mandate applies.
## What this project is
A read-only Python 3.12 tool that compares opening hours and notices for the 24
service points SP-01 to SP-24 across three sources and reports mismatches.
It never writes to the portal, the phone script or the notices spreadsheet.
## Commands
- Set up: `python -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt`
- Test: `python -m pytest`
- Run: `python -m spcheck.cli --week auto` (needs PORTAL_EXPORT, PHONE_EXPORT, NOTICES_EXPORT)
## Where things are
- Code: `src/spcheck/` (sources.py, compare.py, report.py, cli.py)
- Tests: `tests/`. Oracle cases: `tests/oracle/` (written by Saga Edvardsson; read, never edit)
- Specification: `docs/specification.yaml` (SPC-NR-2031-0001). Change only when Hanna asks.
- Synthetic data: `data/synthetic/`
## Rules
- Work on a branch named `assistant/<short-topic>`. Never commit to `main`.
- One small change at a time; run the tests before saying it is done.
- Use only synthetic data. Never open files outside this repository.
- Settings come from environment variables. Never write a value for a secret, a token or a production path into any file.
- Do not edit: `AGENTS.md`, `pipeline.yml`, `tests/oracle/`, `docs/mandate.yaml`, `.gitignore`.
- Add a package only after asking Hanna; say why and what it does.
- When the specification and the code disagree, stop and report; do not choose.
- End each session with a short note: what changed, what was run, what is unfinished.
# AGENTS.md: rules for the assistant in claims-doc-check
Build record BLD-HM-2031-0001. Mandate MND-HM-BLD-2031-01. Owner: Katarzyna Nowak.
These rules restate the mandate; where they differ, the mandate applies.
## What this project is
A Python 3.12 tool that lists the documents still missing from motor
property-damage claim files and drafts a request text for the handler to
review and send. It never decides a claim, never sends a message, never writes
to the claims core and never reads a free-text field.
## Commands
- Set up: `python -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt`
- Test: `python -m pytest`
- Run on synthetic data: `python -m cdcheck.cli --input data/synthetic/claims_synthetic.csv --out out/`
## Where things are
- Code: `src/cdcheck/` (rules.py, check.py, drafts.py, cli.py)
- Rules: `rules.yaml`. Change only when Katarzyna asks, on a written request from the head of claims operations' office.
- Tests: `tests/`. Oracle cases: `tests/oracle/` (written by Marek Zieliński; read, never edit)
- Specification: `docs/specification.yaml` (SPC-HM-2031-0001)
- Synthetic data: `data/synthetic/claims_synthetic.csv` (claim ids SYN-0001 onwards)
## Rules
- Work on a branch named `assistant/<short-topic>`. Never commit to `main`.
- One small change at a time; run the tests before saying it is done.
- Use only synthetic data. Never open the production export, a free-text claim field, a secret or the claims database.
- Log claim ids and counts only.
- Do not edit: `AGENTS.md`, `pipeline.yml`, `tests/oracle/`, `rules.yaml` (unless asked), `docs/mandate.yaml`, `.gitignore`.
- Add a package only after asking Katarzyna; say why and what it does.
- When the specification and the code disagree, stop and report; do not choose.
- End each session with a short note: what changed, what was run, what is unfinished.
A.7 Builder mandate for the assistant
Owned by Chapter 4 (the action classes and ceilings) and Chapter 7 (the full manifest). The mandate says what the assistant may read, change, run and reach, who owns it, who can stop it and what is recorded. The assistant never approves or edits its own mandate. Level 4 Autonomous is not used for any action class. The workspace profile (AIDR-1200, AIDR-1250) is the ceiling; the mandate only lowers it. In the Nordvik Region file the block may_classes is the table of Chapter 4 (read, edit and run at Level 3 Bounded) and the block delegation gives the level per class of work as Chapter 7 does; the two agree because the second is at or below the first.
mandate:
id: MND-NR-BLD-2031-01
version: 1
effective: 2031-10-13
decision: AIDR-1201
subject: approved assistant of the builder workspace, service-point-check (BLD-NR-2031-0001), Mode 2 in the editor and Mode 3 for delegated tasks in the sandbox
usage_modes: [2, 3]
owner: Hanna Wikström
accountable: Gunilla Roos # head of Applications and Integration; approves the mandate
stop_holders: [Hanna Wikström, Maja Lindqvist, platform team on-call]
review_due: 2032-01-13
identity:
issued_by: builder workspace identity service # outside the assistant and the repository
scope: one session, one repository, expires with the session
started_by: Hanna Wikström
may_classes:
- {class: read, scope: [repository, data/synthetic], ceiling: "Level 3 Bounded"}
- {class: edit, scope: [branch], ceiling: "Level 3 Bounded"}
- {class: run, scope: [tests, linters], ceiling: "Level 3 Bounded"}
- {class: commit, scope: [branch], ceiling: "Level 1 Assisted"}
delegation:
specify: {level: 1, note: drafts and questions only; Hanna decides}
generate: {level: 2}
refactor: {level: 2}
test: {level: 2, note: drafts only; never the oracle for the same change}
document: {level: 2}
review: {level: 0}
deploy: none
people: not delegated
may:
- read the repository, its history and the synthetic data in data/synthetic/
- edit files on a branch named assistant/<topic>
- run the test suite and the linters in the sandbox
- read from the package proxy
never:
- read secrets, production data or production configuration
- push to main or trigger the pipeline
- change AGENTS.md, pipeline.yml, tests/oracle/ or this mandate
- install a package that Hanna has not approved
- reach any host not on the proxy allow-list
level_4: {used: false}
budgets: {wall_minutes: 30, tool_calls: 150, files_changed: 20}
notify_owner_when: [a package name is refused by the proxy]
halt_when: [a write to a forbidden path is attempted, a budget is exceeded]
record: RUN-NR-2031-*, written by the sandbox host and not by the assistant
The Hansa Mutual mandate has the same shape. Chapter 7 prints its may and never blocks and its record line; the other fields are composed from Chapters 4, 13 and 16 and from the common facts of the two builds (composed): the same delegation levels, the same budgets and the same review interval as the Nordvik Region mandate.
mandate:
id: MND-HM-BLD-2031-01
version: 1
effective: 2031-10-27
decision: AIDR-1252
subject: approved assistant of the builder lane, claims-doc-check (BLD-HM-2031-0001), Mode 2 in the editor and Mode 3 for delegated tasks in the sandbox
usage_modes: [2, 3]
owner: Katarzyna Nowak
accountable: Joanna Kaczmarek # head of claims operations, Polish service centre
stop_holders: [Katarzyna Nowak, Tomasz Wrona, claims analytics workspace on-call]
review_due: 2032-01-27 # composed: 90 days after adoption
identity:
issued_by: builder lane identity service
scope: one session, one repository, expires with the session
started_by: Katarzyna Nowak
may_classes:
- {class: read, scope: [repository, data/synthetic], ceiling: "Level 3 Bounded"}
- {class: edit, scope: [branch], ceiling: "Level 3 Bounded"}
- {class: run, scope: [tests], ceiling: "Level 3 Bounded"}
- {class: commit, scope: [branch], ceiling: "Level 1 Assisted"}
delegation:
specify: {level: 1, note: drafts and questions only; Katarzyna decides}
generate: {level: 2}
refactor: {level: 2}
test: {level: 2, note: drafts only; never the oracle for the same change}
document: {level: 2}
review: {level: 0}
deploy: none
people: not delegated
may:
- read the repository, its history and data/synthetic/claims_synthetic.csv
- edit files on a branch named assistant/<topic>
- run the test suite in the sandbox
never:
- read the production export, free-text claim fields, secrets or the claims database
- push to main or trigger the group pipeline job
- change AGENTS.md, pipeline.yml, tests/oracle/, rules.yaml without Katarzyna's request, or this mandate
level_4: {used: false}
budgets: {wall_minutes: 30, tool_calls: 150, files_changed: 20}
halt_when: [a write to a forbidden path is attempted, a budget is exceeded]
record: RUN-HM-2031-*, written by the sandbox host and not by the assistant
A.8 Agent run record
Owned by Chapter 10. One record per session of the assistant, written by the sandbox host and read by the builder. It says what was asked, what changed, what was run, what the builder read and what the assistant was refused. It never holds the conversation or any production value. The Nordvik Region record is as Chapter 10 prints it. The Hansa Mutual record is the session of slice 1 in which the assistant copied the collision rule for glass claims (Chapters 10 and 11); the date is composed.
id: RUN-NR-2031-0004
build: BLD-NR-2031-0001
slice: 1
mandate: MND-NR-BLD-2031-01
mode: 3
level: 2
date: 2031-10-22
task: Compare opening hours between portal and phone script (rule R1)
asked: Plan first, then tests, then code; touch only compare.py and its test.
files_changed: [src/spcheck/compare.py, tests/test_compare_hours.py]
tests: {passed: 4, failed: 0}
read_by: Hanna Wikström
diff_notes: Normalisation of 9:00 to 09:00 was added by the assistant after the second test; Hanna asked why and kept it.
refused: The assistant proposed writing corrections back to the portal; declined (never-do).
commit: slice 1 - compare opening hours (R1)
id: RUN-HM-2031-0007
build: BLD-HM-2031-0001
slice: 1
mandate: MND-HM-BLD-2031-01
mode: 3
level: 2
date: 2031-11-04 # composed
task: Write the document-type rules in rules.yaml and the function that loads them (rules R1 and R2)
asked: Plan first, then tests, then code; touch only rules.yaml, rules.py and their tests.
files_changed: [rules.yaml, src/cdcheck/rules.py, tests/test_rules.py]
tests: {failed: 0}
read_by: Katarzyna Nowak
diff_notes: For motor_glass the assistant copied the motor_collision entry, so the accident report stayed in the glass list; the diff was read and the error was not seen. The assistant's tests agreed with the file because the same session wrote both.
refused: none
found_by: independent oracle case glass-03 at Step 7 (VER-HM-2031-0001)
commit: slice 1 - document-type rules (R1, R2)
A.9 Verification plan with the independent oracle
Owned by Chapter 11. The plan says how it is known that the build works: which tests came from the specification, who wrote the oracle cases, that the assistant cannot edit them, what the first run showed, what is not covered and how long the evidence is valid. It never counts the assistant's own tests as the oracle. The Hansa Mutual plan is as Chapter 11 prints it; the Nordvik Region plan is composed from Chapters 4 and 11.
verification_plan:
id: VER-NR-2031-0001
build: BLD-NR-2031-0001
version: v0.1.0
tier: B
spec: SPC-NR-2031-0001 # approved 2031-10-15
generator:
kind: assistant
mandate: MND-NR-BLD-2031-01
run_records: [RUN-NR-2031-0004]
tests:
from_specification: 14 # drafted by the assistant, read by the builder
never_do_cases_tested: [no_write_to_portal, no_write_to_phone_script, no_write_to_notices]
oracle:
owner: Saga Edvardsson # quality engineer; not the builder, not the assistant
cases: 12 # from real notices; no personal data
file: tests/oracle/cases.yaml
assistant_can_edit: false # mandate forbids tests/oracle/; the template places the path outside the sandbox
first_run: 2031-11-05
first_run_result: {passed: 12, failed: 0}
note: A pass is as strong as the cases; they cover holiday closures, shortened hours before a holiday, a service point moved for renovation and a notice that ends on the day of the report.
static_checks: [linter, secret_scan]
not_covered:
- exports larger than those of the synthetic data
- notices written in a language other than Swedish
result_on: 2031-11-05
valid_until: 2032-02-03 # 90 days, or the next change of the code, the rules or the assistant
verification_plan:
id: VER-HM-2031-0001
build: BLD-HM-2031-0001
version: v0.1.0
tier: C
spec: SPC-HM-2031-0001 # approved 2031-10-30
generator:
kind: assistant
mandate: MND-HM-BLD-2031-01
run_records: [RUN-HM-2031-0007, RUN-HM-2031-0011]
tests:
from_specification: 18 # drafted by the assistant, read by the builder
never_do_cases_tested: [no_write_to_claims_core, no_free_text_read, ids_only_in_logs]
oracle:
owner: Marek Zieliński # deputy, senior claims handler; not the builder
quality_sample: head of claims operations' office
cases: 25
file: tests/oracle/cases.yaml
assistant_can_edit: false # mandate forbids tests/oracle/
first_run: 2031-11-08
first_run_result: {passed: 24, failed: 1, failed_case: glass-03}
resolution: rules.yaml motor_glass corrected 2031-11-10; glass example added to SPC-HM-2031-0001
static_checks: [linter, secret_scan]
not_covered:
- claim types other than motor_collision, motor_parking_damage, motor_glass
- languages other than pl, de and en in the draft text
result_on: 2031-11-10
valid_until: 2032-02-08 # 90 days, or the next change of rules.yaml, the code or the assistant
tests/oracle/cases.yaml (one case, written by Marek Zieliński from the claim files; synthetic row):
- id: glass-03
row: {claim_id: ORC-0003, claim_type: motor_glass,
doc_types_received: "photos;repair_estimate", country: PL, language: pl}
expect: {status: COMPLETE, missing: []}
A.10 Review record
Owned by Chapter 11. A person other than the builder and the assistant reads the specification, the verification plan and the diff, in that order, and records what was and was not checked. An AI review comment is read after the person's own reading and never counts as the approval. The Hansa Mutual record is as Chapter 11 prints it. The Nordvik Region record is composed from Chapters 4 and 11: Anders Falk reviewed the code on 2031-11-05 and found one test missing, which the assistant added the same day.
review_record:
id: RVW-NR-2031-0001
verification_plan: VER-NR-2031-0001
reviewer: Anders Falk # integration and data team; the team that will receive the tool
reviewed_on: 2031-11-05
read_in_order: [SPC-NR-2031-0001, VER-NR-2031-0001, diff]
ai_review_comments_read_after: true
ai_review_counted_as_approval: false
checks:
tests: passed
oracle: {cases: 12, passed: 12}
static_analysis: passed
remarks: [no test for a service point absent from one of the three sources (R3); added the same day]
explained_without_the_tool: passed # composed: the builder restated rule R2 from the specification
not_checked: [behaviour under a malformed export larger than the synthetic data]
outcome: approved
review_record:
id: RVW-HM-2031-0001
verification_plan: VER-HM-2031-0001
reviewer: Tomasz Wrona # developer, Group Application Development; receiving developer
reviewed_on: 2031-11-12
read_in_order: [SPC-HM-2031-0001, VER-HM-2031-0001, diff]
ai_review_comments_read_after: true
ai_review_counted_as_approval: false
checks:
tests: passed
oracle: {cases: 25, passed: 25}
static_analysis: passed
explained_without_the_tool: passed # the builder restated the glass rule from the specification
not_checked: [behaviour on exports larger than 50000 rows]
outcome: approved_for_pilot # released v0.1.0 on 2031-11-17
A.11 Provenance record and dependency policy
Owned by Chapter 12. The provenance record states what produced the build (which assistant, under which mandate, in which runs), what it depends on, whether any secret is in the repository, what personal data is in the repository and in the logs, what was not checked and until when the statement holds. The dependency policy is the list of packages that may appear in requirements.txt. Neither holds a secret or a personal value. The Hansa Mutual record and the policy are as Chapter 12 prints them; the Nordvik Region record is composed (pinned versions are those of the Hansa Mutual build, since both builds use the same two packages).
policy_version: 1
rule: every package in requirements.txt must be listed here with a reason
allowed:
- name: pyyaml
purpose: read rules.yaml and the oracle cases
checked: 2031-10-27
checked_by: Tomasz Wrona
- name: pytest
purpose: run the tests
checked: 2031-10-27
checked_by: Tomasz Wrona
provenance_record:
id: PRV-NR-2031-0001
build: BLD-NR-2031-0001
version: v0.1.0
generated_by:
assistant: approved assistant of the builder workspace
mandate: MND-NR-BLD-2031-01
run_records: [RUN-NR-2031-0004]
dependencies:
- {name: pyyaml, pinned: "6.0.2", purpose: read the specification rules and the oracle cases, listed_in_policy: true, exists_in_registry: true, checked_by: Joakim Wester, checked_on: 2031-11-06}
- {name: pytest, pinned: "8.3.4", purpose: run the tests, listed_in_policy: true, exists_in_registry: true, checked_by: Joakim Wester, checked_on: 2031-11-06}
secrets_in_repository: none # the first draft held a token default; the scan stopped the commit on 2031-11-06 and the value was removed
secret_scan: {tool: scripts/scan_secrets.py, run_on: 2031-11-06, result: clean}
personal_data:
in_repository: none
in_logs: none
not_checked: [behaviour under a registry outage]
valid_until: 2032-02-04 # 90 days from 2031-11-06, or the next change
provenance_record:
id: PRV-HM-2031-0001
build: BLD-HM-2031-0001
version: v0.1.0
generated_by:
assistant: approved assistant of the builder lane
mandate: MND-HM-BLD-2031-01
run_records: [RUN-HM-2031-0007, RUN-HM-2031-0011]
dependencies:
- {name: pyyaml, pinned: "6.0.2", purpose: read rules and cases, listed_in_policy: true, exists_in_registry: true, checked_by: Tomasz Wrona, checked_on: 2031-11-13}
- {name: pytest, pinned: "8.3.4", purpose: run the tests, listed_in_policy: true, exists_in_registry: true, checked_by: Tomasz Wrona, checked_on: 2031-11-13}
secrets_in_repository: none
secret_scan: {tool: scripts/scan_secrets.py, run_on: 2031-11-13, result: clean}
personal_data:
in_repository: none # synthetic data only
in_logs: claim ids and counts only
screening: {by: Dr. Sabine Vogel, on: 2031-10-20, decision: AIDR-1251, dpia_required: false}
not_checked: [behaviour under a registry outage]
valid_until: 2032-02-11 # 90 days from 2031-11-13, or the next change
A.12 Pipeline definition: pipeline.yml
Owned by Chapter 13. The pipeline is the only way to production. Its three stages, test, scan and deploy, run under a policy that lives in the platform team's repository, and the deploy stage is promoted by the pipeline's own identity, never by a person and never by the assistant. The assistant may not edit this file, and the gate cannot be changed by the change it checks. The files are in the schema of each organisation's template and are examples of the pattern, not of any product. The Nordvik Region file is as Chapter 13 prints it. The Hansa Mutual file is composed: the tool runs on demand through the group pipeline job claims-doc-check run, with no schedule, and the job's identity reads the production export.
# pipeline.yml for service-point-check, in the schema of the Region's
# scheduled-job template (illustrative; the pattern is the point).
schema: region-scheduled-job/v1
job: service-point-check
python: "3.12"
policy: region-policy/builder-scheduled-job@3 # lives in the platform team's repository
stages:
test:
run:
- python -m pip install -r requirements.lock
- python -m pytest tests/ -q
required: [unit-tests, oracle-cases] # tests/oracle/cases.yaml
scan:
uses: [platform/secret-scan@1, platform/dependency-audit@1]
deploy:
from: tag # only tags vMAJOR.MINOR.PATCH
promoted_by: pipeline-identity # never a person, never the assistant
release_name: "{job}-{version}-b{build}" # for example service-point-check-0.2.0-b3
schedule: "0 6 * * 1" # Mondays 06:00 (from 0.2.0)
environment:
read_only_paths: [PORTAL_EXPORT, PHONE_EXPORT, NOTICES_EXPORT]
secrets: [WIKI_TOKEN] # injected by the platform at run time
timeout_minutes: 10
on_failure: alert:e-services-team-channel
# pipeline.yml for claims-doc-check, in the schema of the group pipeline
# (illustrative and composed; the pattern is the point).
schema: group-pipeline-job/v1
job: claims-doc-check run
python: "3.12"
policy: group-policy/builder-job@2 # lives in Group Application Development's repository
stages:
test:
run:
- python -m pip install -r requirements.lock
- python -m pytest tests/ -q
required: [unit-tests, oracle-cases] # tests/oracle/cases.yaml, written by Marek Zieliński
scan:
uses: [group/secret-scan@1, group/dependency-audit@1, group/log-canary@1] # the canary fails the run if a log line holds more than claim ids and counts
deploy:
from: tag # only tags vMAJOR.MINOR.PATCH
promoted_by: pipeline-identity # never a person, never the assistant
release_name: "claims-doc-check-{version}"
schedule: none # started by handlers in the claims analytics workspace
environment:
production_export: read_by_job_identity_only # never by the builder or the assistant
output_retention_days: 30 # missing.csv and drafts/ are deleted after 30 days
timeout_minutes: 30
on_failure: alert:claims-analytics-workspace-support
A.13 Change record and rollback note
Owned by Chapter 13. The change record says what was released, through which gate, by whom, who reviewed it, how it is undone and who may undo it. It never records that a change is safe without the rehearsal that shows the way back. The Nordvik Region record of version 0.2.0 is as Chapter 13 prints it, with the rollback note that was corrected on 2031-12-12 (the first note named the tag and failed in the takeover test; Chapter 16). The record of version 0.1.0 and the Hansa Mutual record are composed from Chapters 13 and 23.
id: CHG-NR-2031-0002
title: Release 0.2.0 of service-point-check, weekly schedule
build: BLD-NR-2031-0001
class: normal
version: 0.2.0
release: service-point-check-0.2.0-b3
window: 2031-12-08T06:00+01:00
owner: {named: Hanna Wikström, deputy: Elin Berg, ownership_record: OWN-NR-2031-0001}
origin:
assistant: approved assistant of the builder workspace
usage_mode: Mode 3 in a sandbox, delegated tasks on a branch
run_records: [RUN-NR-2031-0014]
merged_by: Hanna Wikström
gate:
definition: region-policy/builder-scheduled-job@3
editable_by_change: false
checks: {unit_tests: 21, oracle_cases: 20, secret_scan: pass, dependency_audit: pass}
oracle_owner: Saga Edvardsson
approvals:
human_review: {by: Anders Falk, record: RVW-NR-2031-0003}
ai_review_counts_as_review: false
promoted_by: pipeline-identity
revert:
previous_release: service-point-check-0.1.0-b2
rollback: jobctl rollback service-point-check --release service-point-check-0.1.0-b2
switch_off: jobctl suspend service-point-check
who_may_use: [Hanna Wikström, Elin Berg, platform on-call]
rehearsal: {date: 2031-12-05, minutes_to_restore: 6, target_minutes: 15, run_by: Hanna Wikström, note_followed_by_another_person: false}
level_4_check: {production_without_gate: false, own_mandate_or_gate_changed: false, irreversible_data_action: false}
records: {mandate: MND-NR-BLD-2031-01, aidr: AIDR-1201}
id: CHG-NR-2031-0001 # composed
title: Release 0.1.0 of service-point-check, on demand
build: BLD-NR-2031-0001
class: normal
version: 0.1.0
release: service-point-check-0.1.0-b2
window: 2031-11-12
owner: {named: Hanna Wikström, deputy: Elin Berg}
origin:
assistant: approved assistant of the builder workspace
usage_mode: Mode 3 in a sandbox, delegated tasks on a branch
merged_by: Hanna Wikström
gate:
definition: region-policy/builder-scheduled-job@3
editable_by_change: false
checks: {unit_tests: 14, oracle_cases: 12, secret_scan: pass, dependency_audit: pass}
oracle_owner: Saga Edvardsson
approvals:
human_review: {by: Anders Falk, record: RVW-NR-2031-0001}
ai_review_counts_as_review: false
promoted_by: pipeline-identity
revert:
rollback: run the previous tag (true for version 0.1.0 only; untrue from version 0.2.0)
switch_off: stop running the tool by hand; the manual weekly comparison resumes
level_4_check: {production_without_gate: false, own_mandate_or_gate_changed: false, irreversible_data_action: false}
records: {mandate: MND-NR-BLD-2031-01, aidr: AIDR-1201}
id: CHG-HM-2031-0001 # composed
title: Release 0.1.0 of claims-doc-check to the pilot team
build: BLD-HM-2031-0001
class: normal
version: 0.1.0
release: claims-doc-check-0.1.0
pre_release: v0.1.0-rc.1 # in the test environment before the release
window: 2031-11-17
ring: pilot team # the first ring; the rest of the handlers see it later
owner: {named: Katarzyna Nowak, deputy: Marek Zieliński, ownership_record: OWN-HM-2031-0001}
origin:
assistant: approved assistant of the builder lane
usage_mode: Mode 3 in a sandbox, delegated tasks on a branch
run_records: [RUN-HM-2031-0007, RUN-HM-2031-0011]
merged_by: Katarzyna Nowak
gate:
definition: group-policy/builder-job@2
editable_by_change: false
checks: {unit_tests: 18, oracle_cases: 25, secret_scan: pass, dependency_audit: pass, log_canary: pass}
oracle_owner: Marek Zieliński
approvals:
human_review: {by: Tomasz Wrona, record: RVW-HM-2031-0001}
ai_review_counts_as_review: false
promoted_by: group-pipeline-identity
revert:
rollback: disable the job claims-doc-check run; the handlers return to the manual check
switch_off: disable the job claims-doc-check run in the group pipeline
who_may_use: [Katarzyna Nowak, Marek Zieliński, claims analytics workspace on-call]
rehearsal: {date: 2031-11-12, minutes_to_restore: 12, target_minutes: 30, run_by: Marek Zieliński, assistant_off: true}
rehearsal_expires: 2032-02-10
level_4_check: {production_without_gate: false, own_mandate_or_gate_changed: false, irreversible_data_action: false}
records: {mandate: MND-HM-BLD-2031-01, aidr: AIDR-1252}
docs/rollback.md (Nordvik Region, as corrected on 2031-12-12; it names the release, not the tag):
# Rollback note: service-point-check
Use when a release produces wrong or missing reports. Owner: Hanna Wikström. Deputy: Elin Berg.
1. Suspend the schedule so that nothing runs while you work:
`jobctl suspend service-point-check`
2. Find the previous release name (the release name, not the tag):
`jobctl releases service-point-check`
3. Roll back through the pipeline:
`jobctl rollback service-point-check --release service-point-check-0.1.0-b2`
4. Run once by hand and compare with the last good report:
`jobctl run service-point-check`
5. Resume the schedule: `jobctl resume service-point-check`
6. Record the rollback in the change record.
CHANGELOG.md entry for version 0.2.0:
## [0.2.0] - 2031-12-08
### Added
- Weekly scheduled run, Mondays 06:00, through the platform's scheduled-job template.
- Report written to the wiki page "Service point check" (rule R1, R2 and R3 findings).
### Changed
- The tool reads the three exports from read-only paths set by the platform.
### Fixed
- Notices that end on a public holiday are now matched to the portal entry.
A.14 Runbook manifest, alerts and restore-test record
Owned by Chapter 14. The runbook lets a colleague who did not build the tool watch it, stop it, restore it and find the person to call. The alert definitions say who evaluates each alert (the platform, not the job), who answers and when each was last tested by causing the failure on purpose. The restore-test record says what was restored, from what, by whom, with the assistant off, how long it took, and what was not tested. None holds export contents, notice text, claim text, names of people outside the team or a secret. The Nordvik Region files are as Chapter 14 prints them. The Hansa Mutual runbook and restore-test record are composed from the paragraph of Chapter 14 and from Chapter 15 (the output files are deleted after 30 days).
id: RBK-NR-2031-0001
version: 2
build: BLD-NR-2031-0001
date: 2031-12-01
purpose: Weekly report of mismatches between portal, phone script and notices (rules R1 to R3)
owner: {named: Hanna Wikström, deputy: Elin Berg}
runs: {schedule: "Mondays 06:00", report_expected_by: "06:15", job_timeout_minutes: 10}
watch:
- {question: did-it-run, check: a successful run exists between 06:00 and 07:00 on Monday, alert: ALR-NR-001}
- {question: did-it-fail, check: last run status is failed, alert: ALR-NR-002}
- {question: is-it-slow, check: run longer than 5 minutes, alert: ALR-NR-003}
- {question: cost, check: platform showback line for this job, reviewed monthly, model_calls_at_run_time: none}
logs:
keep: [run_id, started, finished, status, mismatches_by_rule, service_point_ids]
never: [export contents, notice text, phone numbers, names]
state:
regenerable: [report page (run the job again), release (rebuild from tag)]
backed_up_by_platform: [repository, job configuration]
restore_test: RST-NR-2031-0001
first_hour:
- Read the alert; open the run record; say in the channel who has it.
- "Suspend the schedule if the report may be wrong: jobctl suspend service-point-check"
- If the last release is the cause, follow the rollback note in docs/rollback.md.
- If a source export is missing or malformed, tell its owner (portal team or phone service) and rerun after the fix.
- Write one paragraph in the build record; review it with Elin within a week.
support: [Hanna Wikström and Elin Berg (weekdays 08:00 to 16:00), platform service desk (platform faults), Rasmus Holm's team (code changes, on request)]
manual_fallback: compare the three sources for the 24 service points by hand, using docs/manual-check.md
alerts:
- id: ALR-NR-001
name: job-did-not-run
when: no successful run between Monday 06:00 and 07:00
evaluated_by: platform-scheduler # not by the job itself
to: e-services team channel
answered_by: [Hanna Wikström, Elin Berg]
answer_within: the next working hour
last_tested: {date: 2031-12-04, how: renamed the portal export path in the test environment, received_by: Elin Berg}
- id: ALR-NR-002
name: job-failed
when: last run status is failed
evaluated_by: platform-scheduler
to: e-services team channel
answered_by: [Hanna Wikström, Elin Berg]
answer_within: the next working hour
last_tested: {date: 2031-12-04, how: seeded a malformed notices.csv, received_by: Elin Berg}
- id: ALR-NR-003
name: job-slow
when: "run longer than 5 minutes (observed runs take under 1 minute)"
evaluated_by: platform-scheduler
to: e-services team channel
answered_by: [Hanna Wikström, Elin Berg]
answer_within: the next working hour
last_tested: {date: 2031-12-04, how: added a pause in the test environment, received_by: Hanna Wikström}
id: RST-NR-2031-0001
build: BLD-NR-2031-0001
date: 2031-12-05
claim: service-point-check 0.2.0 can be rebuilt from the repository and the platform configuration alone
scope: [repository at tag v0.2.0, scheduled-job configuration]
objective: {minutes_to_restore: 30}
method: restore_test.sh in a clean workspace, following docs/runbook.yaml only
run_by: Elin Berg
assistant_used: false
result: {outcome: pass, minutes: 11, tests_passed: 21, tests_failed: 0}
not_tested: [platform secret store (platform team's own evidence), manual fallback]
expires: 2032-03-04
id: RBK-HM-2031-0001 # composed
version: 1
build: BLD-HM-2031-0001
date: 2031-11-13
purpose: List the documents missing from motor property-damage claim files and draft request texts for the handler (rules R1 to R4)
owner: {named: Katarzyna Nowak, deputy: Marek Zieliński}
runs: {schedule: "on demand; handlers start the job claims-doc-check run in the claims analytics workspace", job_timeout_minutes: 30}
reads: {input: claims_export.csv, read_by: the identity of the group pipeline job only}
writes: {missing_csv: out/missing.csv, drafts: out/drafts/CLAIMID.txt, retention_days: 30}
watch:
- {question: did-it-fail, check: last job status is failed, alert: workspace support receives it}
- {question: is-it-slow, check: run longer than the timeout, alert: workspace support receives it}
- {question: cost, check: monthly spend limit per builder for the assistant, alert at 80 per cent to Katarzyna Nowak and the lane owner, model_calls_at_run_time: none}
logs:
keep: [run_id, started, finished, status, claim_ids, counts]
never: [claim text, free-text fields, names, addresses]
state:
regenerable: [out/ files (run the job again), release (rebuild from tag)]
backed_up_by_platform: [repository, job configuration]
restore_test: RST-HM-2031-0001
first_hour:
- Read the alert from the workspace support; say who has it.
- If the output looks wrong, disable the job claims-doc-check run; the handlers return to the manual check.
- If the claims export has a new column, the run stops; tell the claims core contact and rerun after the fix.
- Write one paragraph in the build record; review it with Marek Zieliński within a week.
support: [Katarzyna Nowak, Marek Zieliński, workspace support of the claims analytics workspace, Tomasz Wrona (code changes)]
manual_fallback: handlers check the claim file by hand with the handlers' checklist
id: RST-HM-2031-0001
build: BLD-HM-2031-0001
date: 2031-11-14
claim: claims-doc-check 0.1.0 can be rebuilt from the repository and the job configuration alone
scope: [repository at tag v0.1.0, job configuration, synthetic data]
objective: {minutes_to_restore: 30}
method: rebuild from the tag in a clean workspace, following docs/runbook.yaml only
run_by: Marek Zieliński
assistant_used: false
result: {outcome: pass, minutes: 18}
not_tested: [the production export, the workspace's own backups]
expires: 2032-02-12
A.15 Code-ownership record
Owned by Chapter 15. The ownership record says who owns the tool, who is the deputy, who is accountable, where the documents are, how it is kept up to date, when it is reviewed, what happens when the owner leaves and when it ends. It never says that a tool is owned without the deputy's drill. Both records are as Chapter 15 prints them. The Nordvik Region record was written at Tier B and promoted to Tier C in Chapter 16 (AIDR-1203).
id: OWN-NR-2031-0001
status: active
subject:
build: BLD-NR-2031-0001
repository: service-point-check
scope: Weekly comparison of opening hours and notices for service points SP-01 to SP-24
tier: B # promoted to C on 2031-12-15 (AIDR-1203)
owner:
name: Hanna Wikström
role: product owner, e-services team
since: 2031-10-15
deputy:
name: Elin Berg
role: business analyst, e-services team
drill:
kind: explain-it-back
date: 2031-12-02
without_assistant: true
result: passed
accountable: Gunilla Roos
documents:
readme: README.md
specification: docs/specification.yaml
runbook: docs/runbook.yaml
decisions: docs/adr/
handover: docs/handover.yaml
changelog: CHANGELOG.md
updates:
dependencies: monthly, first Monday, branch plus full test run
runtime: follows the platform scheduled-job template
model: none at run time; the build assistant is recorded in MND-NR-BLD-2031-01
review:
confirmed: 2031-12-02
every_days: 90
next_due: 2032-03-01
triggers: [owner or deputy leaves, source export format changes, platform template changes]
owner_leaves:
new_owner_within_days: 30
otherwise: read-only, then archived
sunset:
date: 2033-08-31
renewal: owner shows use and passes review
end_of_life: final release tagged, repository archived with the archivist's agreement
id: OWN-HM-2031-0001
status: active
subject:
build: BLD-HM-2031-0001
repository: claims-doc-check
scope: Missing documents in motor property-damage claim files, with draft request texts
tier: C
out_of_scope: motor_injury
owner:
name: Katarzyna Nowak
role: team lead, motor claims, Polish service centre
since: 2031-10-30
deputy:
name: Marek Zieliński
role: senior claims handler
drill:
kind: explain-it-back
date: 2031-12-03
without_assistant: true
result: passed
accountable: Joanna Kaczmarek
receiving_developer: Tomasz Wrona
documents:
readme: README.md
specification: docs/specification.yaml
runbook: docs/runbook.yaml
decisions: docs/adr/
handover: docs/handover.yaml
changelog: CHANGELOG.md
data:
classes: [claim identifier, claim type, document types received, country, language]
logged: claim identifiers and counts only
data_protection_screening: AIDR-1251
updates:
dependencies: monthly, first Tuesday, branch plus full test run in the group pipeline
rules: rules.yaml changes only on a written request from the head of claims operations' office
model: none at run time; the build assistant is recorded in MND-HM-BLD-2031-01
review:
confirmed: 2031-12-03
every_days: 90
next_due: 2032-03-02
triggers: [owner or deputy leaves, claims export columns change, new claim type in scope]
owner_leaves:
new_owner_within_days: 30
otherwise: job disabled, then archived
sunset:
date: 2033-08-31
renewal: owner shows use and passes review
end_of_life: final release tagged, repository archived under the group's records rules
README.md of the Nordvik Region build, as Chapter 15 prints it (the README must pass the clean-copy run):
# service-point-check
Compares the opening hours and notices of the Region's 24 service points in the
citizen portal, the phone-service script and the notices spreadsheet, and writes a
weekly mismatch report to the e-services wiki.
## What it never does
It never writes to the portal, the phone script or the notices spreadsheet.
It reads and reports only. It holds no personal data of residents.
## Run it
python3.12 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python -m pytest -q
.venv/bin/python -m spcheck.cli --week auto --data data/synthetic
## How it works
sources.py reads the three exports, compare.py applies rules R1 to R3 from
docs/specification.yaml, report.py writes the Markdown report, cli.py ties them together.
## Change it and ship the change
Branch, change, run the tests and the oracle cases in tests/oracle/ (owned by
Saga Edvardsson; do not edit them), open a pull request. The pipeline ships by release name.
## Switch it off, revert, restore
See docs/runbook.yaml and docs/handover.yaml.
## Who to call
Owner Hanna Wikström, deputy Elin Berg, platform team Maja Lindqvist.
## When it ends
2033-08-31 unless renewed. See OWN-NR-2031-0001.
A.16 Handover pack and takeover-test result
Owned by Chapters 4 and 16. The handover pack is a map to the documents that exist, plus the facts that only the pack states: what the tool never does, who the people are, how to run it, change it, ship it, revert it, switch it off and restore it, and what the known risks are. The takeover-test result records what a colleague who did not build the tool could do in one working day. The pack never holds a secret, only the name of where it is kept. The takeover test has ten items, in the order of Chapter 16: T1 find, T2 run the tests, T3 run the tool, T4 change, T5 ship, T6 revert, T7 switch off, T8 restore, T9 explain, T10 secrets. The results below are those of Chapter 16 (6 h 25 min and 5 h 50 min of item time), and the restore-test dates are those of Chapter 14.
id: HND-NR-2031-0001
build: BLD-NR-2031-0001
repository: service-point-check
version: 0.2.0
written: 2031-12-05
revised: 2031-12-12
tier: B # promotion to C decided in AIDR-1203
purpose: Compare opening hours and notices of 24 service points in three sources and report mismatches weekly.
never_does: [write to the portal, write to the phone script, write to the notices spreadsheet]
people:
owner: Hanna Wikström
deputy: Elin Berg
receiving_developer: Rasmus Holm
accountable: Gunilla Roos
platform_contact: Maja Lindqvist
run:
setup: python3.12 -m venv .venv && .venv/bin/pip install -r requirements.txt
tests: .venv/bin/python -m pytest -q # 21 tests, oracle cases in tests/oracle/cases.yaml
report_on_synthetic: .venv/bin/python -m spcheck.cli --week auto --data data/synthetic
scheduled: Mondays 06:00 by the scheduled-job template
data_and_secrets:
classes: public and internal; no personal data of residents
inputs: [PORTAL_EXPORT, PHONE_EXPORT, NOTICES_EXPORT] # read-only paths set by the platform
secret: WIKI_TOKEN # secret store, never in the repository
change:
branch: feature branch, pull request to main
checks: unit tests, oracle cases, review by a named developer
oracle_owner: Saga Edvardsson # the assistant may not edit tests/oracle/
ship:
how: tag the release in the Git service; the platform pipeline deploys by release name
release_name: service-point-check-0.2.0-b3
revert:
to_previous: redeploy the previous release by its release name, not by its tag
rollback_target: service-point-check-0.1.0-b2 # the release name, not the tag v0.1.0
last_tested: 2031-12-12
switch_off: disable the job in the scheduled-job template; the manual weekly comparison resumes
restore: clone the repository, redeploy the release, re-enter WIKI_TOKEN from the secret store (RST-NR-2031-0001, 2031-12-05, passed)
known_risks:
- A change in the portal export format stops the run; the failure alert goes to the e-services channel.
- WIKI_TOKEN expires; renewal is the owner's task.
- The deputy and the owner are in the same team.
decisions: [docs/adr/0001-scheduled-job-template.md, docs/adr/0002-read-only-sources.md, docs/adr/0003-plain-markdown-report.md]
ends: 2033-08-31
id: HND-HM-2031-0001
build: BLD-HM-2031-0001
repository: claims-doc-check
version: 0.1.0
written: 2031-12-04
revised: 2031-12-12
tier: C # since the tier decision of 2031-09-18
purpose: List the documents missing from motor property-damage claim files and draft a request text for the handler to review.
scope: [motor_collision, motor_parking_damage, motor_glass]
out_of_scope: motor_injury # rows are written as OUT_OF_SCOPE and not processed
never_does: [decide a claim, rank handlers or claimants, send a message, write to the claims core, read free-text fields, log more than claim identifiers]
people:
owner: Katarzyna Nowak
deputy: Marek Zieliński
receiving_developer: Tomasz Wrona
accountable: Joanna Kaczmarek
data_protection: Dr. Sabine Vogel # screening AIDR-1251
run:
setup: python3.12 -m venv .venv && .venv/bin/pip install -r requirements.txt
tests: .venv/bin/python -m pytest -q # 18 tests, 25 oracle cases in tests/oracle/cases.yaml
on_synthetic: .venv/bin/python -m cdcheck.cli --input data/synthetic/claims_synthetic.csv --out out/
in_production: handlers start the job "claims-doc-check run" in the claims analytics workspace
data_and_secrets:
classes: claimant personal data (claim identifier, claim type, document types, country, language)
production_export: read only by the identity of the group pipeline; never by the builder or the assistant
secrets_in_repository: none
change:
branch: feature branch, pull request to main, review by the receiving developer
rules: rules.yaml changes only on a written request from the head of claims operations' office
oracle_owner: Marek Zieliński # cases and quality sample; the assistant may not edit tests/oracle/
ship:
how: tag the release; the group pipeline builds and deploys by release name
release_name: claims-doc-check-0.1.0
revert:
to_previous: disable the job; handlers return to the manual check
last_tested: 2031-12-09
switch_off: set the job "claims-doc-check run" to disabled in the group pipeline
restore: clone the repository, redeploy the release by name (RST-HM-2031-0001, 2031-11-14, passed)
known_risks:
- A new column in the claims export stops the run.
- An unknown language value falls back to English drafts (remark R2 of TKT-HM-2031-0001).
decisions: [docs/adr/0001-property-damage-only.md, docs/adr/0002-draft-only.md]
ends: 2033-08-31
id: TKT-NR-2031-0001
build: BLD-NR-2031-0001
handover_pack: HND-NR-2031-0001
version_tested: 0.2.0
run_by: Rasmus Holm # developer, integration and data team; did not build it
date: 2031-12-11
owner_present: false # reachable by telephone; every question counts as a gap
item_time: 06h25m # sum of the items; the test ran 08:30 to 16:30 with breaks
change_task: report a notice whose end date is earlier than its start date as a mismatch
items:
T1_find: {result: pass, minutes: 15}
T2_run_tests: {result: pass, minutes: 25}
T3_run_report: {result: pass, minutes: 30}
T4_change: {result: pass, minutes: 95, note: oracle case for the test branch written by Saga Edvardsson, branch discarded}
T5_ship: {result: pass, minutes: 40, target: test}
T6_revert:
result: fail
minutes: 70
finding: Rollback note names tag v0.1.0; the scheduled-job template accepts a release name only.
gap_questions_to_owner: 1
T7_switch_off: {result: pass, minutes: 20}
T8_restore: {result: pass, minutes: 45}
T9_explain: {result: pass, minutes: 35}
T10_secrets: {result: pass, minutes: 10}
result: fail
fixes:
- {item: T6_revert, action: note names service-point-check-0.1.0-b2, done: 2031-12-12, by: Hanna Wikström}
retest:
date: 2031-12-12
items: [T6_revert]
run_by: Rasmus Holm
result: pass
result_final: pass
evidence_valid_until: 2032-12-11 # sooner if the owner, the receiver or the template changes
promotion:
from: B
to: C
signals: [used by service-point managers in other units, runs unattended from 2031-12-22]
criteria: promotion_criteria.yaml@1.0
met:
name: {owner_and_deputy: true, deputy_drill: 2031-12-02}
understand: {one_page_data_flow: true, independent_cases: 20, written_by: Saga Edvardsson, last_run: 2031-12-12}
revert: {switch_off: 2031-12-11, manual_fallback: 2031-12-10, restore_test: 2031-12-05}
data_and_access: {data_classes_recorded: true, screening: 2031-12-03, dpia_needed: false, anonymous_access: none}
support_and_sunset: {support_path: e-services channel, then integration and data team, review_months: 6, sunset: 2033-08-31}
decided: 2031-12-15
decision_record: AIDR-1203
decided_by: Gunilla Roos
promoted_by: platform-pipeline-identity
id: TKT-HM-2031-0001
build: BLD-HM-2031-0001
handover_pack: HND-HM-2031-0001
version_tested: 0.1.0
run_by: Tomasz Wrona # developer, Group Application Development, Polish service centre
date: 2031-12-09
owner_present: false # reachable by telephone; every question counts as a gap
item_time: 05h50m
change_task: accept video as an alternative to photos for motor_parking_damage
items:
T1_find: {result: pass, minutes: 10}
T2_run_tests: {result: pass, minutes: 20}
T3_run_report: {result: pass, minutes: 25}
T4_change: {result: pass_with_remark, minutes: 105, remark: R1}
T5_ship: {result: pass, minutes: 40, target: test}
T6_revert: {result: pass, minutes: 30}
T7_switch_off: {result: pass, minutes: 15}
T8_restore: {result: pass, minutes: 40}
T9_explain: {result: pass_with_remark, minutes: 55, remark: R2}
T10_secrets: {result: pass, minutes: 10}
result: pass_with_remarks
remarks:
R1:
finding: README does not mention tests/oracle/cases.yaml in its change section; found after the second test run.
action: add the oracle file and its owner to the README
owner: Katarzyna Nowak
due: 2031-12-16
closed: 2031-12-12
R2:
finding: An unknown language value silently produces an English draft that the handler may not notice.
action: count fallbacks in the run summary (counts only, no claim text)
owner: Marek Zieliński
due: 2032-01-13
closed: null
rule: remarks may not concern a gate item; an open remark is reviewed at the next 90-day confirmation
evidence_valid_until: 2032-12-09 # sooner if the owner, the receiver or the pipeline job changes
criteria:
tier: C
reference: promotion_criteria.yaml@1.0
name: {owner_and_deputy: true, deputy_drill: 2031-12-03}
understand: {one_page_data_flow: true, independent_cases: 25, written_by: Marek Zieliński and the quality sample, last_run: 2031-12-09}
revert: {switch_off: 2031-12-09, manual_fallback: 2031-12-09, restore_test: 2031-11-14}
data_and_access: {screening: AIDR-1251, dpia_needed: false, anonymous_access: none}
support_and_sunset: {support_path: claims operations' office, then Group Application Development queue, review_months: 6, sunset: 2033-08-31}
promotion: not applicable; Tier C since 2031-09-18
The request to the receiving developer, in the form Chapter 16 prints it (Nordvik Region):
Request to the receiving developer
Build: BLD-NR-2031-0001, service-point-check 0.2.0, Tier B, Tier C requested
Question: review before promotion; please run docs/handover.yaml, section run
Failing item: none known; the revert section was last tested 2031-12-05
Attached: intent page, HND-NR-2031-0001, build record, RUN records for src/spcheck/compare.py
Needed by: 2031-12-11. After that the weekly report stays manual.
Not asked: a rewrite. Please say what to change and I will make the change.
A.17 Builder learning plan and competence record
Owned by Chapter 21. The learning plan decides the next thing to learn and the tier of build the builder may own; it is shared with the builder, the coach and the second assessor, and it is never used for pay, rating, discipline or telemetry on named persons. The competence record keeps assisted and unaided entries apart, names an assessor outside the line and expires. The Nordvik Region files are as Chapter 21 prints them. The Hansa Mutual plan is composed from the paragraph of Chapter 21 (the opening date and the steps are composed; the second assessor is named by role because the chapter does not name the person).
# BLP-NR-2031-01: builder learning plan (Nordvik Region, illustrative)
id: BLP-NR-2031-01
builder: Hanna Wikström # product owner, e-services
build: BLD-NR-2031-0001 # service-point-check
opened: 2031-11-03
review_every_days: 90
next_review: 2032-02-01
coach: Rasmus Holm # receiving developer
second_assessor: Saga Edvardsson # quality engineer, outside the builder's line
ai_off_block: {hours_per_fortnight: 2, produces: a written artefact and an unaided sample}
purpose: decide the next thing to learn and the tier of build the builder may own
shared_with: [builder, coach, second_assessor]
not_used_for: [pay, rating, discipline, tool telemetry on named persons]
steps:
- order: 1
learn: habits (intent, tier, specification, tests the assistant did not write)
evidence: SPC-NR-2031-0001 approved by someone else
status: met
- order: 2
learn: read a change and explain it in own words
evidence: weekly diff explanation, assistant off, marked by the coach
status: in_progress
- order: 3
learn: write and debug a small function unaided
evidence: unaided work sample, marked by the second assessor
status: planned
stop_sign: personal data of people outside the team, money, or a second unit
# CMP-NR-2031-01: competence record (Nordvik Region, illustrative)
id: CMP-NR-2031-01
person: Hanna Wikström
role: builder, Tier B and C (service-point-check)
recorded: 2031-12-19
assessor: Saga Edvardsson # second assessor, outside the line
valid_days: 180 # evidence about unaided performance
entries:
- skill: frame and specify
condition: assisted
evidence: SPC-NR-2031-0001, rules R1 to R3 and the never-do rule
result: met
date: 2031-10-15
- skill: explain a change
condition: unaided
evidence: 45-minute session on a six-change pull request
result: explained 5 of 6; missed the change to date handling
date: 2031-12-19
- skill: revert
condition: unaided, with the runbook
evidence: RST-NR-2031-0001, drill led by the deputy
result: pass after the rollback note was corrected on 2031-12-12
date: 2031-12-19
reader_limits: [builder, coach, second_assessor]
# BLP-HM-2031-01: builder learning plan (Hansa Mutual, illustrative and composed)
id: BLP-HM-2031-01
builder: Katarzyna Nowak # team lead, motor claims, Polish service centre
build: BLD-HM-2031-0001 # claims-doc-check
opened: 2031-11-10 # composed
review_every_days: 90
next_review: 2032-02-08
coach: Tomasz Wrona # receiving developer
second_assessor: "a developer of Group Application Development who is not the coach"
manager: Joanna Kaczmarek
ai_off_block: {hours_per_fortnight: 2, where: claims analytics workspace, produces: a written artefact and an unaided sample}
purpose: decide the next thing to learn and the tier of build the builder may own
shared_with: [builder, coach, second_assessor, deputy (the plan for the build, not the competence record)]
governed_by: [works agreement KBV-IT-2024-DE, interim Betriebsrat agreement]
not_used_for: [pay, rating, discipline, tool telemetry on named persons]
path: claims analytics development path; leads towards a data analyst's role in claims operations, not towards the development organisation
steps:
- order: 1
learn: habits (intent, tier, specification, tests the assistant did not write)
evidence: SPC-HM-2031-0001 approved by someone else, oracle written by the deputy
status: met
- order: 2
learn: read a change and explain it in own words
evidence: weekly diff explanation, assistant off, marked by the coach
status: in_progress
- order: 3
learn: write and debug a small function unaided
evidence: unaided work sample, marked by the second assessor
status: planned
stop_sign: free-text claim fields, injury claims, or a second centre or market
A.18 Register entry and builder lane
Owned by Chapter 17. The register is the organisation's list of builds; the lane is the provision that makes the sanctioned route easier than the unsanctioned one. The register entry never holds the data itself, only its classes. The Nordvik Region entry and lane are as Chapter 17 prints them, with the restore-test date of Chapter 14 (the chapter prints 2031-12-12).
register: BREG-NR
entry: BLD-NR-2031-0001
name: service-point-check
owner: Hanna Wikström
deputy: Elin Berg
manager: Gunilla Roos
tier: C # B as an on-demand tool; C from scheduled running (AIDR-1203)
tier_decided_on: 2031-12-15
data_classes: [public, internal]
personal_data: none
runs: scheduled, Mondays 06:00, scheduled-job template
receiving_developer: Rasmus Holm
repository: service-point-check
sunset: 2033-08-31
evidence:
tests: {result: pass, date: 2031-12-08, valid_days: 90}
takeover: {result: pass_after_fix, date: 2031-12-12, valid_days: 90}
restore_test: {result: pass, date: 2031-12-05, valid_days: 90}
next_review: 2032-03-04 # 90 days after the oldest evidence
discovered_by: declared
lane: LANE-NR-2031-01
organisation: Nordvik Region
decision: AIDR-1200
opened_on: 2031-10-06
owner: Maja Lindqvist # platform team lead
workspace:
assistant: approved assistant of the builder workspace
usage_modes: [2, 3] # Mode 3 only in the sandbox; Mode 5 not provided
level_4: not used for any action class
data: synthetic only
production_reach: none
secrets: store injects at run time; never in repository or prompt
templates:
- name: builder-template-scheduled-job
for_tiers: [B, C]
version: 0.3.0
pipeline_rules: [secrets_scan, ownership_file, oracle_cases_present, synthetic_data_only]
register: BREG-NR
receiving_developers:
- {name: Rasmus Holm, team: integration and data, allowance: half a day a fortnight per build, first quarter}
support:
office_hours: Tuesdays 14:00-15:00
contact: platform team
service_level_note:
first_response: 2 working days
template_defects_fixed: 10 working days
stop_path: platform team disables the job or revokes the pipeline identity; no prior justification needed
evidence: dry run with a volunteer builder, 2031-10-27, fixes recorded
valid_days: 90
The skeleton of the repository template that the lane provides, in the form Chapter 17 prints it:
builder-template-scheduled-job/
AGENTS.md # rules file for the assistant, signed by the owner
README.md # what the tool is for, how to run it, who to call
pipeline.yml # stages test, scan, deploy; fails on secrets and on missing files
pyproject.toml # pinned dependencies, Python 3.12
src/ # the tool's code
tests/
test_smoke.py # one passing test, so the first pipeline run is green
oracle/cases.yaml # empty, to be filled by someone other than the builder
data/synthetic/ # synthetic data only; the pipeline rejects other files
docs/
build-record.yaml # BLD record skeleton, tier decision, gates
specification.yaml # SPC record skeleton
ownership.yaml # OWN record skeleton: owner, deputy, review dates, sunset
runbook.yaml # RBK record skeleton: start, stop, restore
handover.yaml # HND record skeleton
adr/0001-template.md
CHANGELOG.md
A.19 Checks that can be run mechanically
Owned by Chapters 5, 6, 12, 15 and 21. Each script reads a record from this appendix and reports what is missing or contradictory. A script that passes proves that the record is complete and consistent, not that the build is good: the gate is met by a person reading the artefact. The scripts need Python 3.12 and PyYAML, read files and change nothing. Run them from the repository, for example python3 check_intent.py docs/build-record.yaml, python3 classify_tier.py docs/build-record.yaml, python3 check_ownership.py docs/ownership.yaml 2032-01-15, python3 check_dependencies.py requirements.txt dependency-policy.yaml and python3 check_plan.py docs/learning-plan.yaml 2032-01-15. The scripts are the ones printed in the chapters, unchanged except that the ownership check and the plan check are shown with the file name above them.
check_intent.py: Step 1 gate: is the intent section of a build record complete? Chapter 5.
"""Step 1 gate check: is the intent section of a build record complete?"""
import re
import sys
import yaml
REQUIRED = ["purpose", "user", "problem_now", "success_measure", "done",
"non_goals", "affected"]
def check(record: dict) -> list[str]:
problems = []
intent = record.get("intent") or {}
for key in REQUIRED:
if not intent.get(key):
problems.append(f"intent.{key} is empty")
purpose = str(intent.get("purpose", ""))
if len(re.findall(r"[.!?](\s|$)", purpose)) > 1:
problems.append("intent.purpose is more than one sentence")
measure = intent.get("success_measure") or {}
for key in ("what", "source", "baseline", "target"):
if not measure.get(key):
problems.append(f"success_measure.{key} is missing")
baseline = measure.get("baseline") or {}
if baseline and "value" not in baseline and not (
baseline.get("method") and baseline.get("due")):
problems.append("baseline needs a value, or a method and a due date")
gate = intent.get("gate") or {}
if gate.get("status") == "met":
for key in ("date", "read_back_by", "approved_by"):
if not gate.get(key):
problems.append(f"gate.{key} is missing")
if gate.get("read_back_by") == record.get("builder"):
problems.append("the read-back must be by someone other than the builder")
else:
problems.append("gate is not met")
return problems
if __name__ == "__main__":
with open(sys.argv[1], encoding="utf-8") as handle:
found = check(yaml.safe_load(handle))
print("\n".join(found) if found else "Step 1 gate: met")
sys.exit(1 if found else 0)
classify_tier.py: Step 2: classify a build from the five answers. Chapter 6.
"""Step 2: classify a build from the five answers. A decision aid, not a ruling."""
import sys
import yaml
STOP_SIGNS = {
"ranks_or_decides_about_a_named_person": "ranks or decides about a named person",
"feeds_a_high_risk_ai_system": "is or feeds a high-risk AI system",
"security_critical_path": "sits in a security-critical path",
"irreversible_on_production_data": "acts irreversibly on production data",
}
def classify(answers: dict) -> dict:
stops = [text for key, text in STOP_SIGNS.items() if answers.get(key)]
if stops:
return {"tier": "D", "signals": stops,
"call": ["a developer", "the data protection officer"]}
signals = []
if answers["data"] in ("personal", "special"):
signals.append("personal data of people outside the team")
if answers.get("money"):
signals.append("money")
if answers.get("organisational_record"):
signals.append("a record of the organisation")
if answers["users"] in ("units", "public"):
signals.append("more than one unit")
if answers.get("unattended"):
signals.append("unattended running")
call = []
if answers["data"] in ("personal", "special"):
call.append("the data protection officer")
if answers["data"] == "special":
call.append("a developer, before anything is built")
if signals:
return {"tier": "C", "signals": signals, "call": call or ["a developer"]}
if answers["users"] == "team" or answers["data"] == "internal":
return {"tier": "B", "signals": ["colleagues in one unit use it"], "call": []}
return {"tier": "A", "signals": [], "call": []}
if __name__ == "__main__":
with open(sys.argv[1], encoding="utf-8") as handle:
data = yaml.safe_load(handle)
result = classify((data.get("tier") or data)["answers"])
print(f"Tier {result['tier']}")
for signal in result["signals"]:
print(f" signal: {signal}")
for who in result["call"]:
print(f" call: {who}")
check_dependencies.py: Step 8: fail if requirements.txt names a package the policy does not allow. Chapter 12.
"""Fail if requirements.txt names a package the policy file does not allow."""
import re
import sys
from pathlib import Path
import yaml
def names(requirements: str) -> set[str]:
found = set()
for line in requirements.splitlines():
line = line.split("#")[0].strip()
if line:
found.add(re.split(r"[=<>~!\[; ]", line, maxsplit=1)[0].lower())
return found
def main(requirements="requirements.txt", policy="dependency-policy.yaml") -> int:
allowed = {p["name"].lower() for p in yaml.safe_load(Path(policy).read_text())["allowed"]}
unknown = sorted(names(Path(requirements).read_text()) - allowed)
for name in unknown:
print(f"not in dependency policy: {name}")
return 1 if unknown else 0
if __name__ == "__main__":
sys.exit(main(*sys.argv[1:]))
check_ownership.py: Step 11: check an ownership record. Chapter 15.
"""Check an ownership record: required fields present, review not overdue."""
import sys
from datetime import date, timedelta
import yaml
REQUIRED = ["id", "owner", "deputy", "accountable", "review", "sunset", "documents"]
def check(path, today):
rec = yaml.safe_load(open(path, encoding="utf-8"))
problems = [f"missing field: {k}" for k in REQUIRED if k not in rec]
if problems:
return problems
rev = rec["review"]
if today > rev["next_due"]:
problems.append(f"review overdue since {rev['next_due']}")
if rev["confirmed"] + timedelta(days=rev["every_days"]) != rev["next_due"]:
problems.append("next_due does not follow from confirmed and every_days")
drill = rec["deputy"].get("drill", {})
if drill.get("result") != "passed" or not drill.get("without_assistant"):
problems.append("explain-it-back drill missing or not passed without the assistant")
if today >= rec["sunset"]["date"]:
problems.append("sunset date reached: renew or retire")
return problems
if __name__ == "__main__":
today = date.fromisoformat(sys.argv[2]) if len(sys.argv) > 2 else date.today()
found = check(sys.argv[1], today)
print("\n".join(found) if found else "ownership record in order")
sys.exit(1 if found else 0)
check_plan.py: Builder learning plan check. Chapter 21.
# plancheck.py: check a builder learning plan (PyYAML, Python 3.12)
import sys, datetime as dt, yaml
plan = yaml.safe_load(open(sys.argv[1]))
today = dt.date.fromisoformat(sys.argv[2])
assert plan["second_assessor"] != plan["coach"], "assessor must differ from coach"
assert "pay" in plan["not_used_for"], "the plan must say what it is not used for"
if today > plan["next_review"]:
print("OVERDUE: review of", plan["id"], "was due", plan["next_review"])
else:
print(plan["id"], "ok; next review", plan["next_review"])
for step in plan["steps"]:
print(step["order"], step["status"], "-", step["learn"])
A.20 Reconciliation
The records in this appendix were reconciled with the chapters that own them, and the facts that the chapters established are in docs/EXAMPLE_ORGANISATIONS.md.
Sources
- Nordqvist, G. (2026). AI Developer: How the Developer Role Changes When AI Is Used Broadly in European Enterprises and Public Authorities. The Transformed Architecture, Book 12. (86, Nordqvist, 2026)