📈

LEARN

P1 · Skills · VP · Promotion Planned · P1 design phase Owner: HR/Ops + CHRO (P3 seat)

The skills, VP roll-up, and promotion plane. Hội đồng Chuyên môn (Specialist Council) for peer review. Career-path visualisation. Per-judge scores never ingested.

LEARN owns three intertwined surfaces: (a) a skill catalogue + mastery levels per Member (a skill tree with 1–5 mastery levels per skill, scoped to disciplines like engineering, design, ops, biz); (b) a Voting Power (VP) roll-up computed from PROJ contributions + TIME presence + KB authorship — the input to the REW BP fund's profit-share distribution; and (c) the Hội đồng Chuyên môn (Specialist Council) workflow — 3–5 peer reviewers per promotion case, multi-judge scoring, outcome-only summary. The per-judge individual scores are NEVER exported across the LEARN boundary; only the aggregate summary and the recommendation reach HR. LEARN is EU AI Act Annex III §4 high-risk because promotion decisions are employment-decision automation, and Vietnamese context matters: bằng cấp + chứng chỉ (degrees + certifications) are first-class fields, and the Specialist Council format itself derives from the Vietnamese academic "hội đồng" institution. PRD §9.15 locks the FRs; SRS §4.15 binds them to verification methods.

LEARN is the capability ledger — what each Member can do, how good they are at it, and how that grows into a promotion or sabbatical eligibility milestone. The skill tree is a closed catalogue per discipline (engineering, design, ops, biz, finance); each skill carries a 1–5 mastery scale; each mastery level requires evidence (a project artifact, a KB authorship, an external certification, or a peer endorsement). Voting Power (VP) rolls up from concrete contributions (PROJ, TIME, KB) into a single number per Member that REW uses to weight the annual bonus pool distribution. The Hội đồng Chuyên môn (Specialist Council) is the peer-review workflow that adjudicates promotion cases — 3 to 5 peers per case, multi-judge scoring, outcome-only summary lands at HR.

Status
Planned
P1 · design phase
Est. LoC
~5,500
Rust (axum) + skill catalogue DSL
Planned tests
90+
incl. VP determinism + multi-judge aggregation
Mastery levels
1–5
per skill, per Member
Council size
3–5 judges
per promotion case
Per-judge export
never
(FR pending) enforced at boundary
Depends on
AUTH · HR · PROJ · TIME · KB
VP roll-up inputs
EU AI Act
Annex III §4
promotion = employment decision
1

Why LEARN exists

Without a canonical skills ledger, every promotion conversation devolves into anecdote: "Mai is good at React, right?" — followed by selective memory. With a skills ledger that's evidence-backed (every mastery-level claim ties to a project artifact, a KB post, a cert, or a peer endorsement), the conversation is "Mai's React mastery is at level 4, evidenced by these 3 projects and these 2 KB posts — does the council agree?" The Hội đồng Chuyên môn institutionalises that question and writes the answer down. The VP roll-up turns "contribution" from a feeling into a number that REW can use to weight profit-share fairly. None of this is automatic — humans always decide promotions — but the data substrate makes the decisions explainable, defensible, and (per EU AI Act Art. 13) transparent.

🌳
Skill tree, evidence-backed

Closed catalogue per discipline; each mastery-level claim ties to a concrete artifact (PROJ contribution, KB post, certificate, peer endorsement).

⚖️
Hội đồng Chuyên môn

3–5 peers per promotion case; multi-judge scoring; outcome-only summary. Per-judge data NEVER crosses the LEARN boundary.

🗳
VP roll-up

Deterministic function of PROJ contributions × TIME presence × KB authorship; feeds REW BP fund profit-share distribution.

LEARN is also a sabbatical-eligibility partner: the "every 5 continuous years" tick from HR is the time component; LEARN supplies the qualitative side (knowledge-share post, sabbatical readiness review). Together they decide whether a Member is ready to take their accrued sabbatical now or refine the plan.

2

What it does — 5W1H2C5M

Every cell traces back to PRD §9.15 and SRS §4.15.

AxisQuestionAnswer
5W · WhatWhat is LEARN?A skill catalogue + mastery ledger + VP computation engine + Hội đồng Chuyên môn peer-review workflow + course/training records + career-path visualiser.
5W · WhoWho is touched?Members: own skill profile, learning plan, promotion cases. Council judges: 3–5 peers per case. Owners: HR/Ops operates; CHRO (P3 seat) accountable; CEO is final promotion approver.
5W · WhenWhen does LEARN act?(a) Skill registration / mastery upgrade (continuous); (b) VP recompute (monthly, deterministic); (c) Promotion request (Member-initiated or HR-initiated, quarterly windows); (d) Performance review cycle (HR-initiated, quarterly); (e) Certification expiry tick (90/30/7 days).
5W · WhereWhere does it run?P1: single region (SG-1) backed by AWS RDS Postgres. Per-tenant isolation via row-level security on tenant_id.
5W · WhyWhy a separate module?Because promotion + skills is the most subjective decision in any company, and the only defence against bias is evidence and process. LEARN is the evidence layer.
1H · HowHow does it work?Skill catalogue as Rust + sqlx-backed closed enum per discipline. Mastery claim = row with evidence FK (PROJ contribution id / KB post id / certificate id / endorsement id). VP = pure function of inputs; deterministic. Council workflow is a state-machine per case; per-judge rows stored in LEARN-private table with RLS that excludes HR's read role.
2C · CostCost budget?P1: ~$20/month. 50-tenant: ~$70/month.
2C · ConstraintsConstraints?(a) Per-judge scores never exported ((FR pending)). (b) Promotion gate criteria immutable per parameter version ((FR pending) anti-retroactive). (c) EU AI Act Annex III §4 high-risk; P2 conformity pack. (d) Vietnamese bằng cấp / chứng chỉ fields supported.
5M · MaterialsStack?Rust 1.81 · axum · sqlx · PostgreSQL 16 · async-graphql · NATS for VP-recompute triggers · S3 for certificate PDFs with QR-provenance.
5M · MethodsMethod choices?Closed-enum skill catalogue (no free-text skills). Multi-judge aggregation = median of N scores (resilient to one extreme). Anti-retroactive parameter versioning identical to REW pattern.
5M · MachinesDeployment?Fargate task in SG-1. Multi-AZ Postgres RDS. S3 for cert PDFs.
5M · ManpowerWho maintains?0.25 FTE today (HR/Ops). By P3: CHRO seat + 1 engineer.
5M · MeasurementHow measured?KPIs: promotion-case turnaround (open → closed), per-judge score privacy (= 100%), VP determinism (replay-identical), certification expiry surface rate.
3

Architecture

LEARN is one Rust service with four surfaces (GraphQL subgraph for skill/profile/VP reads, REST admin for council + parameter publishes, MCP narrator surface for the CUO/CHRO-skill, NATS event publisher for VP recompute triggers). The Council Vault is a separate Postgres schema with stricter row-level security — only the LEARN admin role can read per-judge rows; HR's role cannot.

graph TB subgraph CLIENTS ["Clients"] SPA["CyberOS SPA"] MEM["Member portal
(own profile + plan)"] JUDGE["Council judge UX
(per-case)"] CUO["🤖 CUO/CHRO-skill
narrator + recommender"] end subgraph EDGE ["Edge"] AR["Apollo Router
JWT + RBAC"] end subgraph LEARN ["LEARN service (Rust · axum)"] GQL["GraphQL subgraph
Skill · Mastery · VP"] REST["REST admin
council · params · review"] MCP["MCP narrator
read-mostly"] SK["skill_catalogue.rs
closed enum"] MAST["mastery.rs
claim · evidence · review"] VP["vp.rs
deterministic roll-up"] COUNCIL["council.rs
Hội đồng workflow"] PROMO["promotion.rs
case state machine"] CERT["cert.rs
QR-signed PDF gen"] EXPIRY["expiry.rs
90/30/7 day tick"] end subgraph STORES ["Stores"] PG_PUB[("PostgreSQL
skill · mastery · vp_snapshot
RLS by tenant_id")] PG_VAULT[("PostgreSQL
council_vote rows
stricter RLS — HR blocked")] S3[("AWS S3
certificate PDFs
QR-signed provenance")] end subgraph SINKS ["Audit & event"] BRAIN["🧠 BRAIN
learn.lifecycle rows"] OBS["👁 OBS"] NATS["📡 NATS
learn.vp.changed · learn.cert.expiring"] end subgraph DOWNSTREAM ["Consumers"] REW["💎 REW
reads VP for P3 weighting"] HRMOD["👥 HR
review_outcome summary"] KB["📚 KB
course materials"] end SPA --> AR MEM --> AR JUDGE --> AR CUO --> AR AR --> GQL AR --> REST AR --> MCP REST --> SK REST --> MAST REST --> COUNCIL REST --> PROMO REST --> CERT GQL --> VP VP --> PG_PUB MAST --> PG_PUB SK --> PG_PUB COUNCIL --> PG_VAULT PROMO --> PG_VAULT PROMO --> PG_PUB CERT --> S3 EXPIRY --> NATS REST --> BRAIN LEARN --> OBS VP --> REW PROMO --> HRMOD SK --> KB classDef planned fill:#e9d5ff,stroke:#5b21b6 classDef store fill:#f5f3ff,stroke:#7c3aed classDef vault fill:#fee2e2,stroke:#dc2626 classDef sink fill:#f5ede6,stroke:#45210e classDef down fill:#fef6e0,stroke:#9c750a class GQL,REST,MCP,SK,MAST,VP,COUNCIL,PROMO,CERT,EXPIRY planned class PG_PUB,S3 store class PG_VAULT vault class BRAIN,OBS,NATS sink class REW,HRMOD,KB down

Internal components

ComponentPath (planned)Responsibility
skill_catalogue.rsservices/learn/src/skill_catalogue.rsClosed-enum catalogue. Disciplines: engineering, design, ops, biz, finance. ~150 skills total at P1.
mastery.rsservices/learn/src/mastery.rsMastery claim + evidence FK. Levels 1–5; level upgrade requires (evidence + peer endorsement OR council review).
vp.rsservices/learn/src/vp.rsVP roll-up: deterministic pure function over (mastery × discipline weight + PROJ contribution × project weight + KB authorship × kb weight). Versioned parameters.
council.rsservices/learn/src/council.rsHội đồng Chuyên môn workflow. 3–5 judges per case. Anonymous to other judges. Median aggregation. Per-judge rows in vault schema.
promotion.rsservices/learn/src/promotion.rsPromotion case state machine: draft → submitted → council_assigned → in_review → recommended → approved → promoted or rejected.
career_path.rsservices/learn/src/career_path.rsCareer-path visualiser — Member's next-level requirements rendered as a checklist.
cert.rsservices/learn/src/cert.rsInternal certification PDF generator. QR-signed provenance; verify endpoint resolves to LEARN's signed claim.
expiry.rsservices/learn/src/expiry.rsCertification expiry tick — fires learn.cert.expiring at 90/30/7 days. CUO/CHRO-skill notifies Member.
endorsement.rsservices/learn/src/endorsement.rsPeer endorsement of a mastery claim. Cheap and asynchronous; many endorsements; each is a row.
plan.rsservices/learn/src/plan.rsPersonal learning plan — Member-owned, optional council mentor.
training_record.rsservices/learn/src/training_record.rsInternal & external courses; external cert PDFs stored in S3 with member-uploaded metadata.
parameter_version.rsservices/learn/src/parameter_version.rsAnti-retroactive parameter store (mirrors REW pattern). Promotion gate criteria, VP weights, mastery thresholds — all versioned.
narrator.rsservices/learn/src/narrator.rsRead-only MCP narrator — explains promotion criteria, career-path gaps, certification readiness. NEVER reveals per-judge data.
audit_bridge.rsservices/learn/src/audit_bridge.rsWrites lifecycle rows to BRAIN. Per-judge data is structurally absent.
migrations/services/learn/migrations/sqlx migrations. Vault schema with stricter RLS — only LEARN admin can read per-judge.
4

Data model

The schema splits into two zones: the public zone (skill, mastery, VP, promotion case header) readable by HR with appropriate scopes; and the Council Vault (per-judge votes, individual feedback) which only LEARN admin can read. The boundary is enforced at the Postgres role level — HR's read role lacks SELECT on vault tables.

erDiagram MEMBER ||--o{ MASTERY_CLAIM : "asserts" MEMBER ||--|| VP_SNAPSHOT : "current" MEMBER ||--o{ PROMOTION_CASE : "subject of" MEMBER ||--o{ ENDORSEMENT : "gives + receives" MEMBER ||--o{ CERTIFICATION : "earns" MEMBER ||--o{ LEARNING_PLAN : "owns" MEMBER ||--o{ TRAINING_RECORD : "completes" SKILL ||--o{ MASTERY_CLAIM : "level for" DISCIPLINE ||--o{ SKILL : "groups" MASTERY_CLAIM ||--o{ EVIDENCE : "backed by" PROMOTION_CASE ||--o| COUNCIL_PANEL : "reviewed by" COUNCIL_PANEL ||--o{ COUNCIL_VOTE : "contains (vault)" PROMOTION_CASE ||--|| PROMOTION_OUTCOME : "produces summary" DISCIPLINE { string code PK "engineering | design | ops | biz | finance" string display_name decimal weight "for VP roll-up" } SKILL { uuid id PK string discipline_code FK string code "react | postgres | vn-tax | …" string display_name decimal weight "for VP roll-up" } MASTERY_CLAIM { uuid id PK uuid member_id FK uuid skill_id FK int level "1..5" string status "claimed | endorsed | council_reviewed | rejected" timestamp claimed_at uuid superseded_by FK } EVIDENCE { uuid id PK uuid mastery_claim_id FK string kind "proj_contribution | kb_post | external_cert | endorsement" string ref_uri "proj://… | kb://… | s3://…" timestamp recorded_at } ENDORSEMENT { uuid id PK uuid endorser_id FK uuid endorsee_id FK uuid skill_id FK int level "level endorser supports" string note timestamp recorded_at } PROMOTION_CASE { uuid id PK uuid member_id FK string current_level "L2" string target_level "L3" string status "draft | submitted | council_assigned | in_review | recommended | approved | promoted | rejected" uuid initiated_by FK uuid parameter_version_id FK "gate criteria snapshot" timestamp opened_at timestamp closed_at } COUNCIL_PANEL { uuid id PK uuid promotion_case_id FK int judge_count "3..5" uuid chair_id FK } COUNCIL_VOTE { uuid id PK uuid council_panel_id FK uuid judge_id FK int score "1..5" string feedback "private — vault only" timestamp cast_at } PROMOTION_OUTCOME { uuid promotion_case_id PK int aggregate_score "median of judge scores" string recommendation "advance | hold | refine" string summary "outcome only — per-judge data NEVER included" uuid recorded_by FK timestamp recorded_at } VP_SNAPSHOT { uuid member_id PK decimal vp_total "deterministic roll-up" decimal vp_by_engineering decimal vp_by_design decimal vp_by_ops decimal vp_by_biz uuid parameter_version_id FK timestamp computed_at } CERTIFICATION { uuid id PK uuid member_id FK string kind "internal | external" string name string issuer date issued_at date expires_at string s3_pdf_uri string qr_provenance_url } LEARNING_PLAN { uuid id PK uuid member_id FK uuid mentor_id FK string title string status "draft | active | completed | abandoned" timestamp created_at } TRAINING_RECORD { uuid id PK uuid member_id FK string course_code int score "0..100" date completed_at }

VP roll-up formula (versioned · deterministic)

// Pure function. Versioned via parameter_version_id.
// Same inputs → same vp_total. Forever.

fn compute_vp(
    masteries: &[MasteryClaim],   // accepted only
    projects:  &[ProjectContribution],
    kb_posts:  &[KbAuthorship],
    params:    &VpWeights,         // versioned
) -> VpSnapshot {
    let mastery_score = masteries.iter()
        .map(|m| m.level as f64 * params.discipline_weight(m.discipline) * params.skill_weight(m.skill))
        .sum::<f64>();
    let project_score = projects.iter()
        .map(|p| p.contribution_score * params.project_weight(p.project_kind))
        .sum::<f64>();
    let kb_score = kb_posts.iter()
        .map(|k| params.kb_weight(k.post_kind))
        .sum::<f64>();
    let vp_total = mastery_score + project_score + kb_score;
    VpSnapshot {
        vp_total,
        vp_by_engineering: subscore(masteries, "engineering"),
        vp_by_design:      subscore(masteries, "design"),
        // …
        parameter_version_id: params.id,
        computed_at: input_clock(),  // input, not wall clock
    }
}
5

API surface

Three surfaces — GraphQL for skill / mastery / VP reads, REST admin for council + parameter writes, MCP narrator surface for the CUO/CHRO-skill. Per-judge data is never resolvable from any surface.

GraphQL subgraph

extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@key", "@requiresScopes"])

type MasteryClaim @key(fields: "id") {
  id: ID!
  memberId: ID!
  skill: Skill!
  level: Int!
  status: MasteryStatus!
  evidence: [Evidence!]!
  endorsements: [Endorsement!]!
  claimedAt: DateTime!
}

type Skill @key(fields: "code") {
  code: String!
  disciplineCode: String!
  displayName: String!
  weight: Float!
}

type VpSnapshot {
  memberId: ID!
  vpTotal: Float!
  vpByEngineering: Float!
  vpByDesign: Float!
  vpByOps: Float!
  vpByBiz: Float!
  parameterVersionId: ID!
  computedAt: DateTime!
}

type PromotionCase @key(fields: "id") {
  id: ID!
  memberId: ID!
  currentLevel: String!
  targetLevel: String!
  status: PromotionStatus!
  outcome: PromotionOutcome  # summary-only
  openedAt: DateTime!
  closedAt: DateTime
}

type PromotionOutcome {
  aggregateScore: Int!  # median
  recommendation: PromotionRecommendation!
  summary: String!
  # NOTE: no per-judge data exposed here
}

enum MasteryStatus { CLAIMED ENDORSED COUNCIL_REVIEWED REJECTED }
enum PromotionStatus { DRAFT SUBMITTED COUNCIL_ASSIGNED IN_REVIEW RECOMMENDED APPROVED PROMOTED REJECTED }
enum PromotionRecommendation { ADVANCE HOLD REFINE }

type Query {
  myMasteries: [MasteryClaim!]!
  memberMasteries(memberId: ID!): [MasteryClaim!]! @requiresScopes(scopes: [["learn.read"]])
  myVp: VpSnapshot!
  memberVp(memberId: ID!): VpSnapshot! @requiresScopes(scopes: [["learn.vp_read"]])
  myPromotionCases: [PromotionCase!]!
  promotionCase(id: ID!): PromotionCase  # outcome only; per-judge inaccessible
  careerPath(memberId: ID!, targetLevel: String!): [CareerStep!]!
  skills(discipline: String): [Skill!]!
}

type Mutation {
  claimMastery(skillCode: String!, level: Int!, evidenceRef: String!): MasteryClaim!
  endorseMastery(claimId: ID!, supportLevel: Int!, note: String): Endorsement!
  submitPromotionCase(targetLevel: String!): PromotionCase!
  uploadCertificate(input: CertificateInput!): Certification!
}

REST admin surface

MethodPathPurpose
POST/admin/council/panelAssign judges to a promotion case (HR scope).
POST/admin/council/{panel_id}/voteJudge submits score + private feedback (vault).
POST/admin/council/{panel_id}/closeClose the panel; compute median; emit outcome.
POST/admin/promotion/{case_id}/recommendCouncil chair issues recommendation.
POST/admin/promotion/{case_id}/approveCEO approves; HR receives outcome summary; REW notified for compensation_change.
POST/admin/parametersPublish a new parameter version (gate criteria, VP weights). Anti-retroactive replay required.
POST/admin/vp/recomputeTrigger VP recompute for a Member or all Members.
GET/admin/vault/{case_id}Per-judge votes (LEARN admin only; HR scope rejected).
POST/admin/cert/issueIssue internal certification (QR-signed PDF).
POST/admin/dsar/{member_id}/exportDSAR export — own data + endorsements given/received; per-judge scores excluded.

MCP tool catalogue (narrator + recommender · read-only)

Tool nameInputsOutputsAnnotations
cyberos.learn.explain_career_pathmember_id (own), target_levelnarrative checklistreadonly · scope=learn.read
cyberos.learn.recommend_learning_planmember_id (own)plan suggestionsreadonly · narrator-only
cyberos.learn.explain_vpmember_id (own)narrative VP breakdownreadonly · self-scope
cyberos.learn.explain_promotion_outcomecase_idnarrative summary (outcome-only · NEVER per-judge)readonly · scope=learn.read
cyberos.learn.list_skillsdiscipline?Skill[]readonly
cyberos.learn.upcoming_cert_expirymember_id (own)Certification[] expiring <90dreadonly · self-scope
cyberos.learn.draft_endorsementendorsee_id, skill_code, levelendorsement draftdestructive=false · requires human-confirm
6

Key flows

Flow 1 — Skill registration + mastery claim

sequenceDiagram autonumber participant M as Member participant L as LEARN GraphQL participant SK as skill_catalogue.rs participant MAST as mastery.rs participant PG as PostgreSQL participant B as 🧠 BRAIN M->>L: claimMastery(skill="react", level=3, evidenceRef="proj://e-commerce-app") L->>SK: verify skill="react" in catalogue SK-->>L: ✓ L->>MAST: create claim status="claimed" MAST->>PG: INSERT mastery_claim MAST->>PG: INSERT evidence (kind=proj_contribution) L->>B: audit "learn.mastery.claimed" L-->>M: claim created · awaiting endorsement Note over M,B: At least 1 peer endorsement OR a council review
required before status moves to "endorsed".

Flow 2 — Mastery-level upgrade with peer endorsement

sequenceDiagram autonumber participant M as Member (claim owner) participant P as Peer (endorser) participant L as LEARN participant MAST as mastery.rs participant B as 🧠 BRAIN M->>L: claim level=4 for react (current=3) L-->>M: claim created · status="claimed" M->>P: invite to endorse (CHAT notification) P->>L: endorseMastery(claimId, supportLevel=4, note="led the redesign") L->>MAST: insert endorsement; check threshold alt endorsement count ≥ threshold (e.g. 2 peers at target level) MAST->>MAST: status="endorsed" L->>B: audit "learn.mastery.endorsed" else not yet enough endorsements MAST->>MAST: status stays "claimed" L->>B: audit "learn.endorsement.recorded" end Note over M,P: For level-4 → level-5 jumps, council review is mandatory
(parameter-driven threshold).

Flow 3 — Promotion request (full Hội đồng Chuyên môn workflow)

sequenceDiagram autonumber participant M as Member participant L as LEARN participant HR as HR/Ops participant CH as Council chair participant J as Judges 3-5 (anonymous to each other) participant V as Council Vault (private DB) participant CEO as CEO participant REW as 💎 REW participant B as 🧠 BRAIN M->>L: submitPromotionCase(target="L3") L->>L: status="submitted"
parameter_version snapshot taken L->>HR: notify for panel assignment HR->>L: POST /admin/council/panel
{judges: [j1, j2, j3, j4, j5], chair: ch1} L->>L: status="council_assigned" loop each judge J->>L: POST /admin/council/{panel}/vote
{score, private_feedback} L->>V: INSERT council_vote (vault schema) end CH->>L: POST /admin/council/{panel}/close L->>V: aggregate (median score) V-->>L: aggregate + recommendation L->>L: status="recommended"; write PromotionOutcome (summary only) L->>HR: outcome summary (no per-judge data) HR->>CEO: present case CEO-->>L: POST /admin/promotion/{case}/approve L->>L: status="approved" L->>REW: trigger compensation_change (L2 → L3); REW co-sign separately L->>B: audit "learn.promotion.approved" (outcome only) Note over L,B: vault schema rows NEVER cross the LEARN boundary.
HR's DB role lacks SELECT on council_vote.
per-judge data is structurally inaccessible.

Flow 4 — VP recompute (deterministic · monthly)

sequenceDiagram autonumber participant CRON as Monthly cron participant L as LEARN vp.rs participant MAST as mastery store participant PROJ as 🗂 PROJ contributions participant T as ⏱ TIME presence participant KB as 📚 KB authorship participant PARAM as parameter_version store participant PG as vp_snapshot table participant NATS as NATS event bus participant REW as 💎 REW (consumer) CRON->>L: trigger recompute (all Members) L->>PARAM: read current VP weights loop per Member L->>MAST: read accepted masteries L->>PROJ: read contributions (last 12 mo) L->>T: read presence (last 12 mo) L->>KB: read authorship (last 12 mo) L->>L: compute_vp(...) (pure fn) L->>PG: INSERT vp_snapshot end L->>NATS: publish learn.vp.changed (batch) REW-->>NATS: subscriber updates BP fund weighting Note over L,REW: same inputs → same vp_total.
Replay test asserts byte-identical 12-month output.

Flow 5 — Certification expiry surface

sequenceDiagram autonumber participant CRON as Daily cron participant L as LEARN expiry.rs participant PG as PostgreSQL participant NATS as NATS participant CUO as 🤖 CUO/CHRO-skill participant M as Member (CHAT) CRON->>L: tick L->>PG: SELECT cert WHERE expires_at - today IN (90, 30, 7) PG-->>L: 4 rows L->>NATS: publish learn.cert.expiring (×4) CUO-->>NATS: subscriber CUO->>M: "Your AWS Solutions Architect cert expires in 30 days. Plan for renewal?" M->>CUO: "remind in 2 weeks" CUO->>L: schedule follow-up (idempotent)
7

Promotion case lifecycle

A promotion case traverses seven states. Once the parameter_version is snapshotted at submission, the gate criteria for THIS case are immutable — even if the parameters are updated mid-review, this case is judged by the original criteria.

stateDiagram-v2 [*] --> Draft: member starts request Draft --> Submitted: member submits · parameter version snapshotted Submitted --> CouncilAssigned: HR/Ops assigns 3-5 judges + chair CouncilAssigned --> InReview: panel opened · judges casting votes InReview --> Recommended: chair closes panel · median computed Recommended --> Approved: CEO final approval Approved --> Promoted: REW compensation_change recorded Promoted --> [*] Recommended --> Rejected: CEO declines InReview --> Refined: median = "refine" · panel suggests rework Refined --> Draft: member updates evidence Rejected --> [*]

Promotion gate criteria — example (L2 → L3 engineering)

CriterionThresholdSource
VP total≥ 140 pointsvp_snapshot
At least 3 skills at mastery ≥ 43 skillsmastery_claim
Lead role on ≥ 1 project1 projectPROJ contribution.role
At least 5 endorsements (peers ≥ L2)5 endorsementsendorsement
Council median score≥ 4 / 5council_vote (vault)
Time in current level≥ 18 monthsHR contract / level history
Sabbatical knowledge-share post (if eligible)≥ 1KB authorship

Criteria are versioned. Changing them does not retroactively re-judge open cases (anti-retroactive).

8

Functional Requirements

The CyberOS FR catalogue is being rebuilt one feature at a time via the open fr-author Agent Skill.

Previous FR enumerations were archived 2026-05-14 and are no longer reflected on this page. PRD/SRS narrative remains authoritative for the spec; specific FRs land here as they are re-authored.

9

Non-Functional Requirements

PRD §11.2.5 (usability / explainability) and §11.2.3 (security) bind on LEARN. Cross-referenced at nfr-catalog.html#learn.

NFR IDConcernTargetMeasurement
N(FR pending)Per-judge data exposed beyond Council Vault= 0 occurrencesintegration test asserts GraphQL + REST never returns council_vote rows; HR DB role inspection
N(FR pending)Council Vault schema isolationHR + Member roles lack SELECTDB role test in CI
N(FR pending)VP deterministic replay (12-month history)100% byte-identicalreplay job runs nightly, asserts vp_total stable for last 12 snapshots
N(FR pending)Parameter version supersession (no UPDATE on published rows)enforced at DB layermigration grep + DB role inspection
N(FR pending)Career-path next-level checklist completenesscovers 100% of gate criteriaspec test; usability review
N(FR pending)Promotion-case explanation (EU AI Act Art. 13)narrator covers outcome + recommendation + summarynarrator output review at P2 conformity
N(FR pending)VP single-Member compute p95≤ 150 msbench/vp.rs
N(FR pending)VP batch compute (50 Members)≤ 4 sbench/vp_batch.rs
N(FR pending)LEARN availability≥ 99.5%SLO monitor
N(FR pending)Cert expiry alert delivery (post NATS)≤ 60s end-to-endchaos test
N(FR pending)EU AI Act Annex III §4 conformity at P2full conformity packP2 release gate · DPO + CLO sign-off
10

Dependencies

LEARN reads contribution data from PROJ + TIME + KB, identity from HR, and gates by AUTH. Its VP outputs feed REW; its promotion outcomes feed HR (and indirectly REW for the compensation_change).

graph LR subgraph upstream ["LEARN depends on"] AUTH["🔐 AUTH"] HRMOD["👥 HR
Member directory"] PROJ["🗂 PROJ
contributions (VP input)"] TIME["⏱ TIME
presence (VP input)"] KB["📚 KB
authorship (VP input)"] BRAIN["🧠 BRAIN
audit"] OBS["👁 OBS"] end LEARN["📈 LEARN"] subgraph downstream ["LEARN feeds"] REW["💎 REW
VP for P3 weighting"] HRMOD2["👥 HR
review outcome summary"] ESOP["📊 ESOP
milestone grants (optional)"] CUO["🤖 CUO/CHRO-skill"] end AUTH --> LEARN HRMOD --> LEARN PROJ --> LEARN TIME --> LEARN KB --> LEARN BRAIN --> LEARN OBS --> LEARN LEARN --> REW LEARN --> HRMOD2 LEARN --> ESOP LEARN --> CUO classDef planned fill:#e9d5ff,stroke:#5b21b6 classDef shipped fill:#f5ede6,stroke:#45210e class LEARN planned class AUTH,HRMOD,HRMOD2,PROJ,TIME,KB,REW,ESOP,CUO,OBS planned class BRAIN shipped
11

Compliance scope

LEARN is in EU AI Act high-risk scope because promotion is employment-decision automation. Same Annex III §4 classification as REW.

Regulation / standardArticle / clauseLEARN feature that satisfies it
EU AI Act (Reg. 2024/1689)Annex III §4 — Worker managementLEARN is in scope. P2 conformity pack covers risk mgmt, data governance, transparency, human oversight.
EU AI ActArt. 13 — TransparencyCareer-path visualiser; narrator explains promotion criteria; outcome summary disclosed to candidate.
EU AI ActArt. 14 — Human oversight(FR pending): CEO can override council recommendation; council is advisory + Member can dispute.
EU AI ActArt. 9 — Risk managementPer-judge data segregation; anti-retroactive parameter versioning; multi-judge aggregation (no single-judge decision).
Vietnam PDPL (Law 91/2025)Art. 14 — DSARMember DSAR returns own claims/endorsements/cases; per-judge data excluded.
Vietnam Labour CodeArt. 6 — Equal treatmentCouncil judges anonymised to each other; gate criteria identical per level; bias-audit annual.
GDPR (EU 2016/679)Art. 22 — Automated decision-makingCouncil is human-driven; CEO override; right to explanation via narrator.
ISO/IEC 27001:2022A.5.13 — Information labellingCouncil vault classified restricted; per-judge rows tagged.
ISO/IEC 27001:2022A.6.3 — Information security awarenessSkill catalogue includes "security awareness" track at all levels.
SOC 2 Type IICC6.6 — Restricted accessPer-judge data isolated to Council Vault role.
Vietnam Decree 71/2020/NĐ-CPArt. 17 — Foreign degree recognitionExternal certification field with issuer + recognition status.
12

Risk entries

Per-judge data leakage and council bias are the principal risks tracked in the risk register.

IDRiskLikelihoodImpactOwnerMitigation
R-LEARN-001Per-judge score leaks via GraphQL or audit rowLowCatastrophicCSOVault schema · stricter RLS · HR + Member roles lack SELECT · integration test asserts no council_vote in any API response.
R-LEARN-002Council bias (judges from same team, same gender, …)MediumHighCHROPanel-assignment diversity heuristic; annual bias audit; chair-selection rotates.
R-LEARN-003VP drift (kernel non-determinism)MediumHighCTOvp.rs is a pure fn · no clock · no randomness · CI replay asserts byte-identical 12-month history.
R-LEARN-004Retroactive gate-criteria change mid-caseLowHighCHROparameter_version snapshotted at submission; CASE judged against snapshot, not current parameters.
R-LEARN-005Free-text skill creep (catalogue drift)MediumLowHR/OpsClosed-enum at DB layer; new skills require parameter publish (3-way co-sign).
R-LEARN-006External certification fraud (faked PDF)MediumMediumHR/OpsIssuer field + verify URL; HR follow-up on randomly sampled 10%/year; QR-signed provenance for internal certs.
R-LEARN-007Council fatigue (same judges chosen repeatedly)MediumLowCHROJudge-rotation heuristic; max N cases/judge/year; warning if any judge exceeds.
R-LEARN-008EU AI Act conformity gap discovered at auditMediumHighDPO + CLOP2 conformity pack drafted at design; legal review annually.
R-LEARN-009Promotion approval bypasses council (CEO unilateral)LowMediumCEOEU AI Act Art. 14 permits override but requires logged rationale; audit row distinguishes "council-approved" vs "override".
R-LEARN-010VP weights tuned to favour incumbent leadershipLowHighCEO + CHROWeight changes require 3-way co-sign (CEO + CFO + CHRO); anti-retroactive replay; annual fairness audit.
13

KPIs

LEARN health rolls up into 9 KPIs across throughput, integrity, and fairness.

KPIFormulaSourceTarget
Promotion case turnaround (median)median(closed_at - opened_at)LEARN DB≤ 6 weeks
Council judge diversity (gender + team)panels with ≥ 2 dimensions / totalLEARN DB≥ 90%
Per-judge data leak incidentsintegration-test failuresCI= 0
VP determinism replay passreplay passes / runsCI= 100%
Promotion approval rateapproved / submittedLEARN DBtracked · benchmark vs industry
Cert-expiry surface latencymedian(notification - expiry_date_threshold)OBS≤ 1 day
Mastery claim → endorsement (median)median(first_endorsed_at - claimed_at)LEARN DB≤ 14 days
Endorsement coverageendorsed claims / total claimsLEARN DB≥ 80%
EU AI Act conformity scoreitems passed / totalP2 audit= 100%
14

RACI matrix

LEARN is operationally owned by HR/Ops; accountable to CHRO (P3 seat); CEO is the final promotion approver.

ActivityCEOHR/OpsCHROCouncil ChairCSODPOCLO
Skill catalogue maintenanceIRACIII
Promotion case openingIRCIIII
Panel assignmentIRAIIII
Council votingIICA/RIII
Promotion approvalA/RCRCIII
VP weights changeARRCICC
EU AI Act conformity packCICICRA
Bias audit (annual)IRACICC
DSAR (own data)IRIICAC

R Responsible · A Accountable · C Consulted · I Informed.

15

Planned CLI surface

Admin CLI cyberos-learn for HR/Ops + members.

1. Claim a mastery level

$ cyberos-learn mastery claim --skill react --level 4 \
    --evidence "proj://e-commerce-app"

[claim created]
  id:        01HZJ8…
  skill:     react (engineering)
  level:     4 (current 3)
  status:    claimed (awaiting endorsements ≥ 2)
[audit]    brain seq=15201

2. Endorse a peer

$ cyberos-learn endorse \
    --member mai@cyberskill.com \
    --skill react \
    --support-level 4 \
    --note "led the e-commerce redesign; mentored 2 juniors"

[endorsement recorded]
  endorser:  hoa@cyberskill.com
  endorsee:  mai@cyberskill.com
  skill:     react @ level 4
[claim]   status moved: claimed → endorsed (2 endorsements at target level)
[audit]   brain seq=15211

3. Read your career path

$ cyberos-learn career-path --target L3

[career path: L2 → L3 · engineering]

✓ VP total ≥ 140         (current: 152)
✓ 3 skills at mastery ≥ 4 (react ★4, postgres ★4, k8s ★4)
✓ Lead role on ≥ 1 project (e-commerce-app)
✓ 5 endorsements (current: 7)
✗ Council median ≥ 4     (not yet started)
✓ Time in level ≥ 18 mo  (current: 21 mo)

[ready to submit promotion case]

4. Submit a promotion case

$ cyberos-learn promotion submit --target L3

[case created]
  id:                  01HZJ9…
  target_level:        L3
  parameter_version:   2026.04 (snapshotted)
  status:              submitted
  HR notified for panel assignment.
[audit]   brain seq=15221

5. Assign a council panel (HR/Ops)

$ cyberos-learn council assign \
    --case 01HZJ9… \
    --judges hoa@…,linh@…,thanh@…,nam@…,minh@… \
    --chair hoa@…

[panel assigned] 5 judges + chair
[diversity check] 3 teams, 2 genders, 2 levels — heuristic ✓
[audit]   brain seq=15231

6. Read promotion outcome (outcome-only · no per-judge)

$ cyberos-learn promotion outcome --case 01HZJ9…

[case 01HZJ9… · mai@cyberskill.com · L2 → L3]
  status:           recommended
  aggregate_score:  4 / 5 (median)
  recommendation:   ADVANCE
  summary:          "Strong evidence on React mastery, postgres, k8s.
                    Two judges noted leadership growth across 2 quarters.
                    All criteria met. Recommended for advance."

[per-judge data not exposed — vault-isolated]

7. VP recompute (admin)

$ cyberos-learn vp recompute --member mai@cyberskill.com

[recomputing VP for mai@cyberskill.com]
[inputs] mastery=12 claims · proj=4 contributions · kb=3 posts · time=180d
[kernel] pure fn · 0 I/O · 0 randomness
[result]
  vp_total:           152.4
  vp_by_engineering:  118.0
  vp_by_ops:           24.4
  vp_by_biz:           10.0
[params] version 2026.04
[snapshot] vp_snapshot row written
[audit]   brain seq=15241
16

Phase status & estimates

Status
Planned
P1 design phase
Est. LoC (Rust)
~5,500
services/learn + skill catalogue DSL
Planned tests
90+
incl. determinism replay + vault isolation
External libs
~10
axum · sqlx · qrcode · ring · async-graphql
CLI subcommands
~18 planned
cyberos-learn entrypoint
P1 budget
~$20/mo
RDS schema + Fargate share
CapabilityStatus
Skill catalogue (closed enum per discipline)planned · P1
Mastery claim + endorsementplanned · P1
VP deterministic roll-upplanned · P1
Hội đồng Chuyên môn council workflowplanned · P1
Per-judge data vault isolationplanned · P1
Career-path visualiserplanned · P1
Promotion case state machineplanned · P1
Anti-retroactive parameter versioningplanned · P1
External certification + bằng cấp fieldsplanned · P1
Cert expiry tick (90/30/7)planned · P1
Personal learning plans + mentorplanned · P1
Training records + course catalogplanned · P1
QR-signed internal certification PDFsplanned · P2
EU AI Act Annex III §4 conformity packplanned · P2
Annual bias audit frameworkplanned · P2
External LMS content providersplanned · P4
17

References

  • PRD §9.15 — LEARN module FRs ((FR pending) through (FR pending)).
  • PRD §19.15 — LEARN architecture posture, council workflow design.
  • PRD §11.2.5 — Usability NFRs (explainability of automated decisions).
  • SRS §4.15 — Formal (FR pending) through (FR pending) with verification methods.
  • Total Rewards & Career Path Appendix — Promotion gate criteria per level.
  • EU AI Act (Reg. 2024/1689) — Annex III §4 high-risk; Art. 13 transparency; Art. 14 human oversight; Art. 9 risk management.
  • GDPR (EU 2016/679) — Art. 22 automated decision-making safeguards.
  • Vietnam Labour Code (2019) — Art. 6 equal treatment.
  • Vietnam PDPL (Law 91/2025) — Art. 14 DSAR.
  • Decree 71/2020/NĐ-CP — Foreign degree recognition (Vietnamese context for bằng cấp).
  • ISO/IEC 27001:2022 — A.5.13, A.6.3 mapped to LEARN security awareness skill track.
  • Hội đồng Chuyên môn institutional design — Vietnamese academic council format adapted for engineering peer review.
  • Architecture context: services.html#learn.