feat(m1): add kandidatprofil skill with schema reference

This commit is contained in:
Kjell Tore Guttormsen 2026-09-04 21:22:31 +02:00
commit f75718d82c
3 changed files with 425 additions and 0 deletions

View file

@ -0,0 +1,96 @@
---
name: kandidatprofil
description: "Leser, validerer og redigerer kandidatprofilen i arbeidsmappa, og eier den mekaniske sjekken mot build-brief 5.1. Utloeses av vis kandidatprofilen, vis profilen min, valider kandidatprofilen, oppdater lønnsgulvet, oppdater lonnsgulvet, sett opp arbeidsmappa, hvilken versjon kjører jobbsok og hvilken versjon kjorer jobbsok."
triggers:
- vis kandidatprofilen
- vis profilen min
- valider kandidatprofilen
- oppdater lønnsgulvet
- oppdater lonnsgulvet
- sett opp arbeidsmappa
- hvilken versjon kjører jobbsok
- hvilken versjon kjorer jobbsok
---
# kandidatprofil
Eier `profil/kandidat.md` i arbeidsmappa. Frontmatter er absolutt og leses
mekanisk; kroppen er prosa og leses med skjønn. Denne skillen validerer og
foreslår — den skriver aldri i profilen uten at operatøren har sagt ja til
akkurat den endringen.
All operatørrettet tekst er norsk bokmål.
## Løs opp arbeidsmappa først
Arbeidsmappa gjettes aldri. Løsningsrekkefølgen er `--workspace`, deretter
miljøvariabelen `JOBBSOK_WORKSPACE`, deretter en `workspace:`-linje i
`jobbsok.conf` under plugin-datamappa. Svarer ingen av de tre, si det og be om
stien. Ikke anta en hjemmekatalog.
Finnes ikke mappa ennå, kall `scaffold(root)` fra
`${CLAUDE_PLUGIN_ROOT}/scripts/jobbsok_lib/paths.py` og rapporter nøyaktig
hvilke kataloger og filer kallet opprettet. Kallet er idempotent, så en tom
liste betyr at alt allerede var på plass — si det, ikke påstå at noe ble laget.
`beslutninger.jsonl` blir aldri tømt av et scaffold.
## Valider
Kjør den mekaniske sjekken:
```
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/kandidat_schema.py
```
Bruk `validate_file(root, "profil", "kandidat.md")` når du kaller den som
modul. Rapporten er JSON med feltene `gyldig`, `feil`, `advarsler`,
`seksjoner`, `senioritet`, `ansettelsesform`, `absolutte_nei`,
`arbeidssteder`, `vekter_kilde` og `vekter`.
Les rapporten slik:
- **`feil`** er brudd på build-brief 5.1. Hvert element navngir nøkkelstien.
Gjengi stien ordrett til operatøren; ikke omskriv den til prosa.
- **`advarsler`** er ikke feil. En nøkkel utenfor 5.1 er operatørens egen, og
profilen er fortsatt gyldig. Advarselen for `arbeidssteder` sier at
vurderingen faktisk leser nøkkelen — skill den fra en advarsel om en nøkkel
ingenting leser.
- **`vekter_kilde`** er `default` når profilen ikke oppgir `vekter`. Det er en
normal tilstand, ikke et avvik.
- Malformert frontmatter er ingen rapport i det hele tatt: sjekken hever
`FrontmatterError` med linjenummeret. Gjengi linjenummeret.
Hele nøkkellista, seksjonsrekkefølgen, skilletegnkontrakten og standardvektene
står i `${CLAUDE_PLUGIN_ROOT}/skills/kandidatprofil/references/schema.md`. Les
den før du uttaler deg om hva som er påkrevd.
## Der fila og 5.1 er uenige, vinner fila
Operatøren eier denne fila. Foreslå aldri å skrive den om for å passe
kontrakten. Er strukturen ny og fornuftig, er det skjemaet som skal utvides —
si fra om det, ikke rett i fila.
Kroppen er skjønn. Et signaturprosjekt som sier *ikke målt* er en ærlig
tilstand, ikke et hull som skal fylles med et estimat. Et breddepunkt kan være
en disposisjon og ikke et fagfelt.
## Rediger bare som forslag
Ved endringsønske:
1. Les fila og valider den først.
2. Vis diffen — gammel linje, ny linje, og hvorfor.
3. Vent på et eksplisitt ja.
4. Skriv, valider på nytt, og vis den nye rapporten.
Hardfiltrene (`lonn.gulv_nok`, `geografi`, `absolutte_nei`) strammes aldri på
eget initiativ. En serie avslag på lønn er like gjerne et tegn på markedet som
på et feil gulv.
## Versjonsekko
Ber operatøren om versjon, skriv ut begge deler: innholdet i
`${CLAUDE_PLUGIN_ROOT}/BUILD_STAMP` og `version` fra plugin-manifestet
`.claude-plugin/plugin.json`. Mangler stempelfila, si det rett ut i stedet for
å oppgi bare manifestversjonen som om den var hele svaret. Fra M2 er det samme
ekkoet også tilgjengelig fra `dagens`.

View file

@ -0,0 +1,84 @@
# `profil/kandidat.md` — nøkler, seksjoner og vekter
Normativ kilde er `docs/build-brief.md` 5.1. Denne fila gjengir kontrakten slik
den faktisk håndheves, inkludert de utvidelsene som kom av at operatørens egen
fil vant over kontrakten.
## Påkrevd frontmatter — 17 nøkler inkludert nestede
| Nøkkel | Type | Merknad |
| --- | --- | --- |
| `oppdatert` | skalar | dato, `YYYY-MM-DD` |
| `geografi.base` | skalar | stedsnavn, skrives ordrett |
| `geografi.maks_reisetid_min` | heltall | sammenlignes numerisk |
| `geografi.hjemmekontor_min_dager` | heltall | sammenlignes numerisk |
| `geografi.vurderer_flytting` | ord | `ja`, `nei` eller `kanskje` |
| `lonn.gulv_nok` | heltall | avviser mekanisk |
| `lonn.onsket_nok` | heltall | vekter, avviser ikke |
| `lonn.kommentar` | skalar | fri tekst |
| `ansettelsesform.aksepterer` | skalar med kommaliste | se skilletegn |
| `ansettelsesform.avviser` | skalar med kommaliste | se skilletegn |
| `absolutte_nei` | liste | ett punkt per linje |
| `senioritet.min` | fri tekst | ingen enum i 5.1 |
| `senioritet.maks` | fri tekst | ingen enum i 5.1 |
Mangler en av dem, er det en **feil** som navngir nøkkelstien. Mangler hele
blokka, navngis både blokka og hver eneste nøkkel under den.
## Nøkler utenfor 5.1
En ukjent nøkkel er en **advarsel**, aldri en feil. Operatøren eier fila.
| Nøkkel | Status |
| --- | --- |
| `vekter` | additiv, operatørbeslutning 14.3 |
| `arbeidssteder` | utenfor 5.1, men lest av vurderingen |
| alt annet | beholdt, ingenting leser det |
`arbeidssteder` er en flat liste over steder operatøren faktisk vil jobbe.
Står stedet i lista, blir `maks_reisetid_min` en advarsel i stedet for et
avslag for akkurat det stedet.
## Skilletegn
Grammatikken tillater bare en skalar under en mapping-nøkkel. Derfor bærer
skalaren lista, med én regel som gjelder likt overalt:
- **komma** deler en skalar i elementer
- **skråstrek** deler ett element i alternative skrivemåter
- **mellomrom** inne i et alternativ er en frase
Så `åremål/engasjement, vikariat` er to avviste former, den første med to navn.
`personalansvar / linjeledelse` er ett nei med to navn. Regelen gjelder
`ansettelsesform.aksepterer`, `ansettelsesform.avviser` og hvert punkt i
`absolutte_nei`.
Prisen er at en ansettelsesform ikke kan inneholde komma. Ingen gjør det.
## Kroppsseksjoner, i rekkefølge
1. Kjerne
2. Kompetanse
3. Retning
4. Signaturprosjekter
5. Kjente svakheter
6. Formuleringer som virker
7. Profilgap
Bare `##` teller. En `#`-tittel øverst og `###`-underseksjoner inni er lov og
er ikke seksjoner i 5.1-forstand. Feil rekkefølge er en feil; innholdet inne i
en seksjon valideres ikke.
## Standardvekter
| Kriterium | Standard |
| --- | --- |
| `fagomrade` | 40 |
| `oppgavetype` | 30 |
| `teknologi` | 20 |
| `selskapstype` | 10 |
Oppgir profilen `vekter`, gjelder de i stedet og rapporten sier
`vekter_kilde: profil`. Manglende kriterium arver standarden og gir en
advarsel. Vektene normaliseres på summen, så tallene trenger ikke summere til
100 — de gjør det bare for at vektoren skal leses som en fordeling.