BREADCRUMBS
This commit is contained in:
parent
4ad78b57b1
commit
475888ad01
45
Workday/Planning/Breadcrumbs/Gemini.md
Normal file
45
Workday/Planning/Breadcrumbs/Gemini.md
Normal file
@ -0,0 +1,45 @@
|
||||
Here is a prioritized list of high-value tasks you can complete right now in your local workday-mcp environment:
|
||||
|
||||
1. Expand the "Mismatch" Logic (WIS-014 – WIS-018)
|
||||
You’ve built the Manager scanner, but a true Identity Sync needs to detect several other types of drift.
|
||||
|
||||
Job Title Mismatch: Build a tool to compare "Workday Title" vs "AD Title".
|
||||
|
||||
Department Drift: Identify workers whose cost center in Workday doesn't match their AD Department string.
|
||||
|
||||
Legal Name vs. Preferred Name: Build logic to handle cases where AD uses a "Display Name" that differs from the Workday "Legal Name".
|
||||
|
||||
Status Reconciliation: Create a tool that specifically flags "Terminated" in Workday but "Enabled" in AD.
|
||||
|
||||
2. Implement Schema Validation (WIS-010)
|
||||
Instead of just returning "any" dictionary, use a library like pydantic to enforce a strict contract.
|
||||
|
||||
The Build: Create a WorkerModel that defines exactly what fields are required (e.g., employee_id must be a string of a certain length).
|
||||
|
||||
The Test: Write a script that tries to "break" your tools by feeding them bad data to see if your error handling catches it gracefully.
|
||||
|
||||
3. Build a "Dry Run" Comparison Tool (WIS-019)
|
||||
Before you ever automate a "Write" to Active Directory, you need a tool that simulates the change.
|
||||
|
||||
The Logic: Create a tool that takes a Workday record and an AD record (both mocked for now) and returns a "Diff" object.
|
||||
|
||||
Output Example: {"field": "department", "old": "Sales", "new": "Marketing", "action": "update"}.
|
||||
|
||||
4. Hardening & Security (WIS-027 & Priority 6)
|
||||
Prepare for the "Production" environment requirements.
|
||||
|
||||
Log Redaction: Update your server to ensure that if an error occurs, it doesn't print sensitive data (like emails or IDs) to the console/logs.
|
||||
|
||||
Environment Configuration: Move your "Constants" (like port numbers or mock file paths) into a .env file and use the python-dotenv library to load them.
|
||||
|
||||
Rate Limiting Simulation: Workday APIs have limits. Build a "decorator" for your tools that simulates a delay or a "429 Too Many Requests" error to test how your server handles it.
|
||||
|
||||
5. Documentation & "Self-Service" (WIS-027)
|
||||
Build an MCP Resource: MCP supports "Resources" (read-only files). Create a resource that serves a "Data Dictionary" explaining what every Workday field means.
|
||||
|
||||
Installation Script: Write a simple setup.sh or setup.bat that automates the creation of the .venv and installation of requirements for the next person who joins the project.
|
||||
|
||||
6. Unit Testing (The "Quality" Pillar)
|
||||
Pytest Integration: Create a /tests folder and write tests that verify your get_worker_manager logic for all three scenarios (Found, Not Found, No Manager).
|
||||
|
||||
CI/CD Simulation: Set up a local Git Hook that prevents you from committing code if it has Pylance errors or failing tests.
|
||||
279
Workday/Planning/Breadcrumbs/Microsoft Copilot.md
Normal file
279
Workday/Planning/Breadcrumbs/Microsoft Copilot.md
Normal file
@ -0,0 +1,279 @@
|
||||
Perfect — this gives us the **real-world shape** of the Workday record we should design around, *before* you ever get API access. Based on what you pasted, your **Employee ID is numeric (8 digits)** and you have a stable set of “Job Details” + “Public Contact” fields we can treat as your **Phase 1 canonical Worker contract**. [\[wheelsinc-...epoint.com\]](https://wheelsinc-my.sharepoint.com/personal/castn1_wheels_com/Documents/Microsoft%20Copilot%20Chat%20Files/server.py)
|
||||
|
||||
Below I’m going to do two things:
|
||||
|
||||
1. Translate your Workday profile into a **clean canonical schema** (fields, types, constraints) that you can enforce with Pydantic (**WIS-010**) now.
|
||||
2. Show how that schema feeds your **dry-run diff tool** (**WIS-019**) and your later Workday→AD sync logic—without needing Workday access yet.
|
||||
|
||||
***
|
||||
|
||||
## 1) What your profile tells us about “employee\_id” (and constraints)
|
||||
|
||||
From your profile:
|
||||
|
||||
* `Employee ID` = `10016638` → **numeric string**, **8 digits** (at least in your tenant).
|
||||
* This is a **better primary key** than email or name for matching to AD.
|
||||
|
||||
### Recommended constraint (for now)
|
||||
|
||||
* Treat `employee_id` as a **string** (not int) to preserve leading zeros if they exist in other records.
|
||||
* Enforce pattern: `^[0-9]{8}$` (8 digits)
|
||||
|
||||
> If you later discover IDs vary (e.g., 6–10 digits), you can loosen the regex to `^[0-9]{6,10}$` without breaking downstream contracts.
|
||||
|
||||
***
|
||||
|
||||
## 2) Canonical Worker Schema (Phase 1 / no Workday API required)
|
||||
|
||||
Here’s a **normalized Worker model** derived from your field list. I’m using names that are stable + automation-friendly, while keeping the original Workday labels clear.
|
||||
|
||||
### Field mapping (Workday → canonical)
|
||||
|
||||
**Identity**
|
||||
|
||||
* `employee_id` ← Employee ID (string, 8-digit numeric)
|
||||
* `work_email` ← Email (string, email format)
|
||||
|
||||
**Org / Reporting**
|
||||
|
||||
* `supervisory_organization` ← Supervisory Organization (string)
|
||||
* `manager_name` ← Supervisory Organization trailing manager name (string, optional)
|
||||
* `manager_employee_id` ← (not present in your paste; optional until Workday API provides it)
|
||||
|
||||
**Job**
|
||||
|
||||
* `position` ← Position
|
||||
* `business_title` ← Business Title
|
||||
* `job_profile` ← Job Profile
|
||||
* `employee_type` ← Employee Type (e.g., Regular)
|
||||
* `management_level` ← Management Level (e.g., Individual Contributor)
|
||||
* `time_type` ← Time Type (e.g., Full time)
|
||||
* `fte_percent` ← FTE (decimal percent)
|
||||
|
||||
**Employment dates**
|
||||
|
||||
* `hire_date` ← Hire Date (date)
|
||||
* `original_hire_date` ← Original Hire Date (date)
|
||||
* `continuous_service_date` ← Continuous Service Date (date)
|
||||
|
||||
**Location**
|
||||
|
||||
* `location` ← Location
|
||||
* `work_address` ← Work Address (string)
|
||||
|
||||
### Why this specific cut matters
|
||||
|
||||
This set gives you enough to drive:
|
||||
|
||||
* onboarding timing (hire date)
|
||||
* basic directory attributes (title, department-like org fields, location)
|
||||
* reporting chain resolution (supervisory org / manager)
|
||||
* future group mapping (job profile, employee type, management level)
|
||||
|
||||
…and it’s stable enough to validate *before* Workday access.
|
||||
|
||||
***
|
||||
|
||||
## 3) How I’d update your current MCP server **right now** (targeted improvements)
|
||||
|
||||
Your current `server.py` is a solid scaffold, but it’s using:
|
||||
|
||||
* mock IDs like `EMP001`, and
|
||||
* a flat dict with fields (`name`, `status`, `dept`, `email`, `manager_id`) [\[wheelsinc-...epoint.com\]](https://wheelsinc-my.sharepoint.com/personal/castn1_wheels_com/Documents/Microsoft%20Copilot%20Chat%20Files/server.py)
|
||||
|
||||
To align with *real Workday data* **before you ever connect**:
|
||||
|
||||
### A) Switch your mock dataset to real ID format
|
||||
|
||||
Change mock keys from `EMP001` → `10016638` style.
|
||||
|
||||
* This forces you to solve input validation and casing issues now (numeric IDs have no casing).
|
||||
* It prevents later refactors when Workday is live.
|
||||
|
||||
### B) Standardize your tool outputs (strongly recommended)
|
||||
|
||||
Right now, tools return either:
|
||||
|
||||
* a worker dict OR
|
||||
* `{"error": ...}` [\[wheelsinc-...epoint.com\]](https://wheelsinc-my.sharepoint.com/personal/castn1_wheels_com/Documents/Microsoft%20Copilot%20Chat%20Files/server.py)
|
||||
|
||||
Before Workday access, lock in a stable envelope like:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"data": { ... },
|
||||
"error": null,
|
||||
"meta": {
|
||||
"correlation_id": "uuid",
|
||||
"source": "mock",
|
||||
"contract_version": "wis.v1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Why now? Because Power Automate + connectors love consistent shapes. If you wait, you’ll end up rewriting flows and schemas later.
|
||||
|
||||
### C) Build Pydantic models for:
|
||||
|
||||
* Worker input (`WorkerModel`)
|
||||
* Tool response (`WorkerStatusResponse`)
|
||||
* Error (`ErrorModel`)
|
||||
* Envelope (`ToolResponse[T]`)
|
||||
|
||||
This is the core of **WIS-010**.
|
||||
|
||||
***
|
||||
|
||||
## 4) Concrete Pydantic Contract Proposal (WIS-010)
|
||||
|
||||
Here’s the **contract design** I recommend based on your profile fields and your automation goals.
|
||||
|
||||
### WorkerModel constraints (recommended)
|
||||
|
||||
* `employee_id`: `^[0-9]{8}$`
|
||||
* `work_email`: must validate as email
|
||||
* `fte_percent`: 0–100 (float)
|
||||
* `time_type`: enum (`Full time`, `Part time`, etc.)
|
||||
* Dates: parsed into real `date` objects
|
||||
|
||||
### “Strict mode” recommendation
|
||||
|
||||
Start with:
|
||||
|
||||
* `extra="forbid"` (reject unknown fields)
|
||||
* later relax to `extra="ignore"` if Workday payloads contain extra fields you don’t care about
|
||||
|
||||
This gives you confidence early.
|
||||
|
||||
***
|
||||
|
||||
## 5) Your Dry-Run Diff Tool (WIS-019) — now shaped by real Workday fields
|
||||
|
||||
Once you validate Workday-shaped inputs, your dry-run diff becomes meaningful:
|
||||
|
||||
### What it should compare (Phase 1 scope)
|
||||
|
||||
From the fields you pasted, your first drift checks should include:
|
||||
|
||||
* Title / Business Title / Job Profile
|
||||
* Location
|
||||
* Manager / supervisory org reference
|
||||
* Employee status → AD enabled/disabled state
|
||||
* Email → UPN/mail alignment
|
||||
|
||||
### Diff item example (your intended format + enhancements)
|
||||
|
||||
You suggested:
|
||||
|
||||
```json
|
||||
{"field":"department","old":"Sales","new":"Marketing","action":"update"}
|
||||
```
|
||||
|
||||
I’d add two fields **now** that become critical in Phase 3:
|
||||
|
||||
* `severity` (low/medium/high)
|
||||
* `reversible` (true/false)
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"field": "business_title",
|
||||
"old": "Team Lead, Deskside Support",
|
||||
"new": "Team Lead, Deskside Support",
|
||||
"action": "none",
|
||||
"severity": "low",
|
||||
"reversible": true
|
||||
}
|
||||
```
|
||||
|
||||
Then your approval payload can be generated directly from the diff result (no extra logic later).
|
||||
|
||||
***
|
||||
|
||||
## 6) Break Tests you can run **today** (with your real constraints)
|
||||
|
||||
Since we now know your ID shape, your “try to break it” script should include:
|
||||
|
||||
### Employee ID failure cases
|
||||
|
||||
* empty string `""`
|
||||
* non-numeric `"EMP001"`
|
||||
* wrong length `"1001663"` (7 digits), `"100166380"` (9 digits)
|
||||
* whitespace `" 10016638 "`
|
||||
|
||||
### Data failures (WorkerModel)
|
||||
|
||||
* invalid email `"not-an-email"`
|
||||
* FTE out of range `150.0`
|
||||
* Hire date invalid `"2021-13-40"`
|
||||
* Missing required fields (`employee_id`, `work_email`)
|
||||
|
||||
### Expected behavior
|
||||
|
||||
* Tools return `ok:false`
|
||||
* Error has stable code (e.g., `VALIDATION_ERROR`)
|
||||
* No sensitive fields are echoed in logs (see below)
|
||||
|
||||
This is how you prove WIS-010 is real, not theoretical.
|
||||
|
||||
***
|
||||
|
||||
## 7) Security/Hardening decisions informed by your profile fields
|
||||
|
||||
Because Workday records contain PII-like data (email, address), your hardening step (WIS-027) should **explicitly redact**:
|
||||
|
||||
* `work_email`
|
||||
* `work_address`
|
||||
* `employee_id` (optional partial mask like `******38`)
|
||||
|
||||
### Redaction policy (recommended)
|
||||
|
||||
* In logs: redact always
|
||||
* In tool responses:
|
||||
* keep email if the tool is intended for automation and access is controlled
|
||||
* or provide a config switch: `RETURN_PII=false` (defaults safe)
|
||||
|
||||
This is much easier to implement now than after Workday is live.
|
||||
|
||||
***
|
||||
|
||||
# 8) What I would change in your current `server.py` (actionable list)
|
||||
|
||||
In order, **before Workday API access**:
|
||||
|
||||
1. **Replace EMP### mock IDs with numeric employee IDs** (like your `10016638`) [\[wheelsinc-...epoint.com\]](https://wheelsinc-my.sharepoint.com/personal/castn1_wheels_com/Documents/Microsoft%20Copilot%20Chat%20Files/server.py)
|
||||
2. **Add Pydantic WorkerModel + Response envelope** (WIS-010) [\[wheelsinc-...epoint.com\]](https://wheelsinc-my.sharepoint.com/personal/castn1_wheels_com/Documents/Microsoft%20Copilot%20Chat%20Files/server.py)
|
||||
3. **Normalize tool outputs** into `{ok,data,error,meta}` for every tool [\[wheelsinc-...epoint.com\]](https://wheelsinc-my.sharepoint.com/personal/castn1_wheels_com/Documents/Microsoft%20Copilot%20Chat%20Files/server.py)
|
||||
4. **Implement dry\_run\_compare() tool** returning a typed DiffResult (WIS-019)
|
||||
5. **Add rate-limit simulation decorator** and make errors explicitly retryable (WIS-027)
|
||||
6. **Add log redaction helper** for email/address/employee\_id (WIS-027)
|
||||
7. **Externalize mock data** into JSON + support multiple scenario datasets
|
||||
8. **Pytest suite**: manager resolution scenarios (Found/Not Found/No Manager) using your mock structure [\[wheelsinc-...epoint.com\]](https://wheelsinc-my.sharepoint.com/personal/castn1_wheels_com/Documents/Microsoft%20Copilot%20Chat%20Files/server.py)
|
||||
9. **Pre-commit hooks** to block commits on failing tests/lint
|
||||
|
||||
***
|
||||
|
||||
## 9) Two quick questions so I lock the schema correctly
|
||||
|
||||
1. In your tenant, is **Employee ID always 8 digits**, or have you seen contractors/vendors with a different format?
|
||||
2. Do you want **Work Address** treated as:
|
||||
* a field you *store* in AD/Entra, or
|
||||
* *reference only* (used for location logic but not written anywhere)?
|
||||
|
||||
***
|
||||
|
||||
## If you want, I can take the next step automatically
|
||||
|
||||
If you say “go,” I’ll draft:
|
||||
|
||||
* A **Pydantic schema pack** (`models.py`) for WorkerModel, DiffResult, Envelope
|
||||
* A revised `server.py` that:
|
||||
* uses numeric employee IDs
|
||||
* returns consistent envelopes
|
||||
* includes `dry_run_compare`
|
||||
* includes redaction + rate-limit simulation toggles
|
||||
* A `/tests` folder with the manager tests + “break tests” script
|
||||
|
||||
Just tell me whether you prefer **Pydantic v1 or v2** (most orgs are v2 now, but I’ll match your repo dependency reality).
|
||||
3
Workday/Planning/Breadcrumbs/README
Normal file
3
Workday/Planning/Breadcrumbs/README
Normal file
@ -0,0 +1,3 @@
|
||||
# Breadcrumbs
|
||||
|
||||
- Folder contains info and ideas to get back on the path after vacation.
|
||||
Loading…
x
Reference in New Issue
Block a user