MdgSuite — User Manual

This manual covers the day-to-day workflows for WMS operators and tenant ADMINs. If you are looking for the architecture, data model, or SECS/GEM heritage, read The Agentic Org instead.

Audience: tenant ADMIN (full access to setup pages) and warehouse OPERATOR (day-to-day app usage). Where a section is ADMIN-only we mark it explicitly.

🔑 Sign in & 2FA

MdgSuite uses a two-factor authentication flow: email + password, then a 6-digit TOTP code from an authenticator app (Google Authenticator, Authy, 1Password, Bitwarden, any RFC-6238 compliant app).

1

Enter email and password

On the login screen, type your full email and password. If your company uses a bare username (e.g. marco), the system appends the tenant's default domain for you.

2

First-ever login — enrol TOTP

A QR code appears. Scan it with your authenticator app. The app now shows a rotating 6-digit code. Type the current code on screen to confirm enrolment. From now on, this is your second factor.

3

Subsequent logins — type the code

After email + password, the app asks for the current 6-digit code. Type it. You are in.

Lost your phone? You need an ADMIN to reset your 2FA. The reset button lives on your user row in Admin → Users (not Security Setup — that page is policy-only). After a reset you go through the first-ever login flow again at your next sign-in.

🔒 Passwords & PINs

Password policy

The default policy requires at least 8 characters, including:

Your tenant ADMIN can tighten this further in Security Setup but never loosen it.

Badge PIN vs password

WMS operators sign in at the warehouse terminal with a badge code + PIN — typically 4 or 6 digits. This is not the password. Passwords are for the web app; PINs are for the terminal. You can change either one from the user profile menu.

Reset policy. Only ADMINs can reset another user's password or PIN. You can always change your own from the profile menu without ADMIN intervention.

🏡 First-tenant bootstrap (ADMIN)

A fresh WMS instance lands without any tenant provisioned. The first person to log in creates the tenant by supplying a company name on the login form alongside their email and password.

The system:

  1. creates a dedicated tenant database mdgwms_<id>
  2. seeds default settings (warehouses, CCNL, governance defaults)
  3. promotes you to ADMIN for that tenant
Once provisioned, no further tenant bootstrap is offered from this URL. Additional tenants on the same backend require an existing ADMIN to explicitly create them (roadmap: Create new customer button in the admin area).

🧠 Agent chats — how they work

MdgSuite ships with a virtual C-suite. Each persona owns a different lens on the business; you interact through a chat window pinned to the relevant context (plan, job, or the current company as a whole).

PersonaOwnsTypical questions
COO Plan quality, bottlenecks, operational rebalancing «Where's the backlog?», «Who's overloaded this week?», «Why did score regress vs last week?»
CFO OT budget, SLA tardiness cost, rebalance churn «How far are we from the weekly OT budget?», «If I raise MaxOT to 120 minutes, what's the euro delta?»
CHRO CCNL caps, consent renewals, rest windows «Anyone at risk of breaching weekly overtime?», «Which operators need a consent refresh this month?»
Planner The active plan on a specific job/run «Rebalance Sara from picking to packing», «Why is mission X unscheduled?», «What if I raise send-ahead to 40%?»
CMO Customer SLA risk, ship-late patterns, post-sale complaint trends «Which customers are at risk of missing their SLA this week?», «Who is accumulating non-conformities?», «Any recurring ship-late to a single customer?»
QA Shelf-life exposure, storage-class compliance, QC pass-rate trend «Which lots are inside the block-ship window?», «Any incompatible items in the same bin?», «Is the QC pass rate slipping this week?»
CEO
read-only
Cross-domain synthesis. Reads CFO / COO / CHRO / QA / CMO memories and writes an executive briefing. Never applies actions — names the persona who should. Send an empty message for the daily briefing. «Give me a one-bullet summary per domain for today.», «What are the two decisions I need to take this week?»
Cross-persona awareness. When you ask the COO about overtime, it may fetch an opinion from the CFO before replying («CFO says 118% of budget, I suggest moving one operator instead of approving OT»). This is the event-bus mesh — you see a single coherent answer, not a stitched email chain.

🍭 Action pills

When the agent proposes to do something (update a setting, run a plan, rebalance), the proposal lands as a coloured pill at the end of the chat bubble. The colour tells you the outcome:

PillMeaningAction
✓ applied Action ran automatically (within the Governance threshold). The system state has already changed. Nothing to do — verify the change if you want.
⏸ pending Action is above the autonomy threshold (e.g. HIGH impact). Waiting for a human decision. Click Approve on the pill OR approve from Telegram if configured. See Approve & reject.
· skipped The agent linked you to the right admin page instead of acting. Common when the proposed change is out of the agent's scope. Follow the link and edit manually.
⚠ failed Action was attempted but the backend rejected it (validation, conflicting state, network). Hover the pill for the reason. Fix the precondition or ask differently.

Contextual buttons

Some pills carry extra buttons:

When the Planner says «Applico…». The COO/Planner prompt was tightened on 2026-04-19: when you ask to apply or recalculate something («cap OT at 60 and recompute», «ricalcola», «applica»), the reply is in present tense («Applico X. Impatto: Y.») and always carries the ACTION tag. You should see green ✓ applied pills, not a promise to act. If you only see prose with no pill, that's a bug — please report it.

🧭 What-if simulations

The Planner can recompute the current plan with temporary setting overrides — overtime cap raised, spillover target lowered, MaxOT per day bumped, an operator marked absent, and so on. The tenant's real defaults are never touched until you explicitly promote the override. This is the day-to-day what-if tool.

Trigger a what-if

Open the 💬 Chat with the Planner section on the UFCP page (WMS) or on a specific Job (UFCP SaaS) and phrase the question as a hypothetical. Examples in plain English or Italian:

The Planner invokes one of the tools scoped to simulation (update_setting with scope=Job, then rerun, or one of apply_rebalance / apply_level / apply_absence) and recomputes. The tenant's default settings are not changed — only this Job's SettingsOverrideJson is.

The SIMULATION banner

Above the plan summary a yellow banner appears with the label SIMULATION, a one-line summary of what was changed (e.g. «MaxOtMinutesPerDay: 90 → 120»), and two buttons on the right. Expanding the banner lists every override field-by-field.

As long as the banner is visible, every number on the page — Gantt, daily capacity, violations, plan score — reflects the simulated plan, not the tenant default.

Discard vs Promote

ButtonWhat it doesWhen to use
Discard override Clears this Job's SettingsOverrideJson and recomputes with the tenant defaults. The banner disappears. The simulated result is worse, or you were just exploring. Safe, reversible, LOW impact — no approval needed.
Promote to tenant default Copies the override values into the tenant-wide UFCP / CFO / CHRO setting rows. From now on every new plan for this tenant uses the new values. The simulation is the direction you want the whole business to go. HIGH-impact action: lands as ⏸ pending unless the tenant's autonomy threshold is HIGH. Approve from the chat pill or Telegram.
Session override vs tenant default. The override lives on one specific Job (the current calculated plan). It survives the user's browser session and a page reload, but a different Job does not see it. Promoting is the only way to make the change stick beyond this Job.

Named simulations — the SIM badge

When the Planner runs apply_rebalance, apply_level, or apply_absence, the clone is saved with an auto-generated Label (max 80 chars) summarising what changed — for example:

You see this label everywhere the Job shows up: the Simulations page, the UFCP page header, the chat pill that offers to open the clone. Any Job that carries a SettingsOverrideJson override also carries a small SIM badge next to its status — it's the visual cue that you're looking at a what-if, not at a canonical plan.

The UFCP page job-header bar

After you press Calculate Plan or open a Job from the Simulations page, a thin header bar appears above the plan view: a short Job id + an editable Label input + a Save button. Use it to rename a simulation in place before you share the link with a colleague. An empty label clears the name (back to «no label»); the endpoint behind the button is PATCH /api/jobs/{id}/label (WMS) or PATCH /v1/jobs/{id}/label (UFCP).

The Simulations page

Open 🧪 Simulations from the WMS sidebar (under the Agents collapsible section, next to the chats) to get a list of your recent Jobs. One row per Job, each with:

Why label a simulation? Before named simulations, comparing scenario A and scenario B meant remembering which Job id belonged to which idea. Now you label Scenario A — cap OT 60 and Scenario B — MaxSpread off and the Simulations page reads like a log. This is also the integration point for the upcoming side-by-side scenario library — the data model is already there.

Comparing scenarios

Today there is no automated side-by-side diff — each what-if replaces the previous one on the same Job, and clone-based actions (apply_*) produce distinct Jobs. To compare two scenarios end-to-end:

  1. Run scenario A via the chat. The clone gets an auto-label; rename it from the Simulations page if you want something shorter.
  2. Go back to the original Job (same page, the parent Job id is in the header), run scenario B.
  3. Open Simulations and compare metrics between the two clones — OT minutes, unscheduled count, plan score. Click each Open to inspect the Gantt.

A dedicated side-by-side diff (metric table rendered for two Jobs at once) is on the roadmap.

The CCNL is the floor. A simulation can only tighten CCNL caps, never loosen them. If you ask the Planner for «MaxOT=200» and the CCNL allows 120, the override is clamped at 120 and the Planner tells you so. Always check the banner for the actual values used.

✅ Approve & reject

Every action has an impact level: LOW, MEDIUM, HIGH. Each tenant sets an autonomy threshold in Agent Governance. Actions at or below the threshold are auto-applied; higher-impact actions land as ⏸ pending and wait.

Approve from the chat

  1. Scroll to the pending pill in the chat.
  2. Click Approve.
  3. The pill turns ✓ applied or ⚠ failed depending on the backend's validation.

Reject from the chat

Click Reject on the pending pill. The action is archived as rejected_action with your user id — the agent will not propose the exact same thing again within 24 hours.

Timeouts are fail-closed. If nobody approves a pending action within the tenant's ApprovalTimeoutMinutes window (default 60), the system auto-rejects it with reason via=timeout. Never assume a forgotten pending will eventually apply itself.
Everything lands in Agent Decisions. Every approve, reject, auto-apply and timeout writes a structured row to Agent Decisions. When you want to review what happened overnight or audit a specific action, open that page instead of scrolling the Chamber.

📱 Telegram approval

If the tenant has Telegram configured, high-impact pending actions also land as a message in a chosen chat with inline Approve and Reject buttons. Tapping one of them closes the loop the same way the in-chat pill does.

Setup (ADMIN)

  1. Create a Telegram bot via @BotFather and keep the bot token.
  2. Add the bot to a private chat with yourself (or a team channel); send /start so Telegram records your chat id.
  3. In MdgSuite open Agent Governance, fill Telegram Bot Token and Telegram Chat Id, save.
  4. Go to Telegram Setup and click Install webhook. The bot now forwards button presses back to MdgSuite.
Security. Telegram callbacks are authenticated by a per-tenant HMAC secret derived from the bot token. A wrong or missing header is silently dropped. Only chat ids on the allow-list are accepted. Losing the bot token is a security event — rotate it immediately from BotFather and paste the new value into Agent Governance.

⚖ Agent Governance (ADMIN)

One-page control of how autonomous the agents can be. Tenant-wide settings, applied to every persona.

FieldWhat it does
AutoApproveEnabled Master switch. When off, every action the agent proposes lands as ⏸ pending regardless of level — classic human-in-the-loop.
AutoApproveMaxLevel Highest impact level the system applies without asking. READ_ONLY = read-only actions only (nothing is auto-applied in practice today). LOW = auto-apply LOW only. MEDIUM (default) = LOW + MEDIUM. HIGH = everything, including HIGH. Use HIGH only in non-production tenants.
ApprovalTimeoutMinutes After this many minutes a pending action is auto-rejected (fail-closed). 0 means «never expire» — only set this if you have operational discipline to clear pending rows manually.
AutonomousEnabled Master switch for the autonomous decision runtime (observe → decide → apply). Off by default — tenants opt in explicitly once they trust the ecosystem enough to let agents act without a human triggering the chat. When on, background agents may propose actions on every tick; the usual AutoApproveMaxLevel gate still applies to each proposal.
DailyActionBudget Hard cap on auto-applied background actions per tenant per UTC day. Once the count is reached, the autonomous runtime skips further dispatches until the next midnight rollover. Default 5. This is the safety net against a runaway agent spamming the system.
AutonomousShadowMode Trust-builder switch. Off by default. When on the autonomous runtime keeps ticking on its normal cadence and keeps running every agent's decide step, but every proposal lands as ⏸ pending on Agent Decisions regardless of impact level — your AutoApproveMaxLevel is ignored while shadow is on. You review each row by hand and approve or reject with the normal pills. Use it for weeks of real traffic before flipping it off and letting auto-apply actually happen.
TelegramBotToken & TelegramChatId Out-of-band approval channel. See Telegram approval.
Turning on autonomy responsibly. The recommended three-step roll-out:
  1. Flip AutonomousEnabled = true and AutonomousShadowMode = true at the same time. The background runtime starts ticking; every proposal lands ⏸ pending on Agent Decisions so you can review what the agents would have done without them actually doing it.
  2. Let it run for at least a couple of weeks of real traffic. Walk the Agent Decisions feed, read the rationales (Input JSON), approve the good ones by hand, reject the bad ones, and let the 30-day Outcome tile build up a verdict history.
  3. Once you trust the proposal quality, flip AutonomousShadowMode off. The same agents now auto-apply up to AutoApproveMaxLevel. Keep DailyActionBudget small (3–5) at first and raise only after a week of healthy auto-applies.

📡 Observer Setup (ADMIN)

Each C-level persona has a background observer that ticks on its own schedule. Use this page to turn them on/off and set the interval per persona.

Enabled: the persona is allowed to wake. Interval: minutes between scheduled ticks (5–1440). Last / Next run: for observability — lets you confirm ticks are actually happening.

Polling + interrupt. The interval you set here is the ceiling. In addition to the cadenced tick, the observer wakes sub-second when a peer writes a high-severity concern (the A#2 event bus). Polling is the safety net in case an interrupt is missed; you never need to rely on one alone.
Autonomous runtime also wakes on the bus (shipped 2026-04-19). Until today the autonomous runtime only ticked on its own 5-minute timer. From wave 3, a HIGH-severity concern from any observer also wakes the runtime sub-second through the same bus — the router added a pseudo-persona called AUTONOMOUS that receives every HIGH-severity event alongside the real C-levels. End-to-end path: observer writes a HIGH concern → bus notifies → autonomous runtime immediately runs its three agents for the tenant → the dispatched proposal lands in Agent Decisions and the summary lands in the Chamber as an autonomous_action. The 5-minute timer stays as the fallback for missed NOTIFY deliveries, so you still see activity even if the bus connection is reconnecting. In practice: if you flip a production agent that raises a HIGH concern, the autonomous proposal now appears in the audit log within a second or two — no waiting for the next poll.

Typical values:

📋 Tenant Knowledge (ADMIN)

Until this page existed, everything the agent «knew» about your company had to be inferred from the memory corpus — past plans, concerns, chat turns. Tenant Knowledge is where you write it down explicitly: binding rules the agent must respect, soft preferences it should lean on, and date-scoped exceptions (an operator on holiday, a plant-wide closure). Everything you enter here is read by every agent chat on every turn and by the WMS scheduler every time you press Calculate Plan.

The page lives under the 🤖 Agents sidebar group and carries six tabs (Patterns and User Attrs closed the step-2 follow-up on 2026-04-19):

First-time walkthrough

1

Open the page and click 📚 Load examples

The button seeds 12 editable templates (4 policies + 4 preferences + 4 exceptions). These are examples, not hidden defaults — you are expected to edit or delete them. Nothing in them is treated specially by the engine.

2

Adapt a policy or preference

Click into any cell and edit inline. The App, Category, Recurrence and TargetType cells are controlled dropdowns with short explanations; the rest is free text. Column headers carry tooltips — hover the ⓘ marker next to each header if you are unsure what a field means.

3

Add a concrete exception

Say Giuseppe Verdi is off on 21 April 2026. On the Exceptions tab: set TargetType user, TargetRef giuseppe.verdi@your-domain (the Identity email, the display name if unambiguous, or the WMS BadgeCode all work — case-insensitive), Recurrence once, Rule «Vacation». The StartDate / EndDate fields do not yet have a date picker in the UI — set them via PATCH /api/tenant-knowledge/exceptions/{id} with a JSON body {"startDate":"2026-04-21","endDate":"2026-04-21"} until the picker ships.

4

Open the Preview prompt tab

Confirm that under ### Active exceptions (CURRENT WINDOW) you see a line like «user giuseppe.verdi@… — Vacation (2026-04-21)». If the line is missing, the recurrence or the date range does not cover today — re-check them. If the block is entirely empty, nothing gets injected and the agent behaves as before.

5

Run Calculate Plan in WMS

On 21 April 2026 Giuseppe must not appear in the resulting plan — the scheduler now treats his user-targeted exception identically to an AbsenceCode on his operator calendar. The same holds for global exceptions: they short-circuit scheduling tenant-wide for their active dates. For v1, all other TargetType values (resource, group, item, customer, supplier) are surfaced to the chat via the system prompt but do not yet steer the scheduler; the agent reads them and you approve manually.

How to think about it

Where the data lives. The three tables sit in the per-company mdgagent_<companyId> DB — the same one that holds AgentMemoryItem and AgentDecisionLog. A company that runs both WMS and UFCP shares one rulebook; the same policy applies in both hosts.

💰 CFO Setup (ADMIN)

Thresholds the CFO uses to decide whether to raise a concern.

FieldMeaning
OvertimeRatePerMinuteEuro/minute used to convert OT minutes into euros.
OvertimeWeeklyBudgetIf the last 7 days of plans exceed this, a concern is raised.
UnscheduledAccumulationAlertDaysHow many consecutive days with unscheduled work triggers a capacity concern.
MaxRebalancesPerWeekA concern is raised when total rebalances across plans in the last 7 days exceed this — symptom of mis-sized departments.
SlaTardinessThresholdDaysCumulative tardiness across recent plans above this raises an SLA-risk concern.

🧑‍⚖️ CHRO Setup (ADMIN)

Policy guardrails on top of the CCNL master data. The CCNL itself is the hard floor — these settings can only make the rule stricter, not looser.

FieldMeaning
MaxOvertimeCapOverrideMinutesPerDay Optional tenant-wide override of the CCNL daily OT cap. Must be ≤ the CCNL limit.
MinRestHoursOverrideOptional minimum rest between shifts — again, must tighten the CCNL floor, not relax it.
ConsentRenewalMonthsHow often a night-shift or special-task consent must be renewed. The CHRO observer raises concerns when a consent is expiring or expired.
EnforcementModeOn a CCNL breach: WARN (concern only) or BLOCK (concern + the plan is marked unshippable).

📊 COO Setup (ADMIN)

Objective weights and strategy priority the Planner uses when generating a plan. The COO observer watches the drift of the resulting plan score over time.

🛡 Security Setup (ADMIN)

Tenant-wide security policy. Per-user actions (reset password, reset 2FA, reset badge, unlock) live on the Users page — Security Setup is just the policy layer.

Policy knobs

Nothing in this page is per-user. If you are looking for the button to reset a specific operator's password, clear their lockout, or wipe their 2FA enrolment, go to Admin → Users.

👥 Users (ADMIN)

Roster of the operators in this tenant. Per-user actions all live here — they are audited (the user and the ADMIN who clicked are recorded in the tenant audit log).

Per-user reset actions

Other actions

Do not share ADMIN credentials — every reset row in the audit log pins the action to whoever pressed the button. Accountability breaks down when two people share an account.

🤖 AI Setup (ADMIN)

Configure which AI provider powers the agents. MdgSuite supports Anthropic (Claude), OpenAI (GPT), Google (Gemini), and Ollama (local). All four can be enabled at once; the priority order decides cascade.

  1. Pick a provider, paste the API key. The key is encrypted at rest.
  2. Choose the default model. Some hints:
    • Anthropic: claude-sonnet-4-5 (balanced) or claude-opus-4-5 (deepest reasoning).
    • OpenAI: gpt-4o (balanced) or gpt-4.1.
    • Gemini: gemini-2.5-flash.
    • Ollama: qwen2.5:7b runs comfortably on a single GPU.
  3. Set Max tokens and Temperature. Defaults are 2048 / 0.3 — low temperature favours consistent, auditable replies.
  4. Set Priority. Lower = tried first. If the top provider times out, the cascade moves to the next.
Tool-calling is native on all three cloud providers. When the agent reasons «ask a peer before replying», it uses each provider's native function-calling API (no text-tag parsing). Ollama still uses the text-tag fallback because local tool-call support is uneven.

🗣 Agent Chamber

A read-only timeline of what the agents have been doing. Use it to audit autonomous actions, read concerns, or simply follow along while work happens.

Entry kinds

Filters & search

Ping widget. The health strip at the top of the Chamber sends a SECS/GEM-style S1F1 Are You There ping to each persona (1:1 or broadcast). Useful to confirm observers are alive and to see when the last tick happened without scrolling the timeline.

🔎 Agent Decisions (ADMIN)

The Chamber shows agent activity as a narrative timeline — useful to follow along. Agent Decisions, reached from the same menu group, is the structured audit trail: every action that reaches the dispatcher lands here as a row, regardless of whether it came from a chat click, a Telegram button, or the autonomous runtime. Use it to answer questions like «what did the agent do last week and why did it think it was the right call?».

What's in each row

The 30-day summary tile

The top of the page shows an Outcome — last 30 days rollup: five counters (positive / neutral / negative / inconclusive / not-yet-evaluated) plus a per-persona breakdown with an average Δ score column. A negative average means the agents of that persona, on balance, improved the plan over the window — that is the single number to trust when answering «is autonomy paying off?» for a tenant.

Filters

The filter bar accepts any combination of persona, action code, status, from, to. Results are newest-first and hard-capped at 200 rows per page; use the Prev / Next buttons to walk back in time.

The detail modal

Clicking Open on a row reveals four JSON blocks:

Where the data lives. The rows come from the per-company AgentDecisionLog table in mdgagent_<companyId> — the same DB that holds AgentMemoryItem. When a company runs both WMS and UFCP, both hosts write into the same log, so the Agent Decisions page in either PWA shows a unified view.

What an autonomous proposal looks like

When the autonomous runtime (not a chat turn) produces a row, the Trigger column reads background. As of 2026-04-19 three agents can populate those rows: AutonomousRebalanceAgent (persona COO), AutonomousCfoBudgetAgent (persona CFO), AutonomousChroComplianceAgent (persona CHRO). Read them by opening the detail modal and scanning the Input block — the agent puts its rationale there in plain prose next to the raw numbers. The two new personas read as follows:

Both proposals respect AutonomousShadowMode: while shadow is on they land pending regardless of level. Once you flip shadow off, LOW (CFO budget) is inside the default AutoApproveMaxLevel = MEDIUM and auto-applies; MEDIUM (CHRO compliance) also auto-applies under the default, but we recommend keeping the CHRO proposals in manual review for a bit longer than the CFO ones — they move a global cap that affects every upcoming plan.

Thumbs-up / thumbs-down on a decision

Clicking Open on a row now also surfaces two buttons next to the outcome pill: 👍 Useful and 👎 Bad call. Pressing one writes your vote against the baseline plan memory that bracketed the decision:

🧩 Memory Browser & GDPR (ADMIN)

Before this page existed, the only way an admin could inspect what the agents remembered about the company was to open a SQL client and query mdgagent_<companyId> by hand. The Memory Browser page (under 🤖 Agents, 🧩 icon, ADMIN-only) now exposes that corpus as a plain table with filters, per-row delete, and two GDPR controls at the top.

Browsing the corpus

  1. Open 🤖 Agents → Memory Browser.
  2. Set the filters you care about: Kind (plan, concern, action, interaction, meeting, ...), Role (the producing persona — COO, CFO, CHRO, ...), UserId (if you're hunting for everything tied to a specific user), Take (default 100, max 500).
  3. Press Search. The raw rows come back ordered by most recent first, with columns for CreatedAt, Kind, Role, App, Content (truncated to 400 chars with a «...» expand), FeedbackScore (the number in [-1, +1] described above), and UserId.
  4. Click the inline 🗑 icon on any row to delete just that entry. Useful to scrub a single stale concern without touching the rest of the history.

GDPR Article 15 — export a user's data

Type the target user's UserId (a GUID; grab it from the Admin → Users roster) into the top control bar and press Export JSON. The browser downloads a agent-memory-export-<userId>.json file containing:

Send this bundle to the data subject. It satisfies the right of access without you writing any SQL.

GDPR Article 17 — purge a user's data

Irreversible. There is no undo. Always run Export JSON first and keep the file under internal retention before pressing purge.
  1. Fill the UserId field with the target GUID.
  2. Fill the Display name field with the exact name the agents have been using in free-prose memory (e.g. «Mario Rossi»). This is important: some memory rows reference the user by name inside their Content rather than by UserId — without the display name, those rows would survive.
  3. Press Purge all for user. You will be asked to confirm twice.

The backend then deletes: every memory whose UserId matches OR whose Content contains the display-name substring, plus every UserAttribute attached to the user. You get a count of deleted rows back.

Same surface on UFCP. The same page with the same two controls exists in the UFCP PWA for companies running the planner. Since WMS and UFCP of the same company share mdgagent_<companyId>, running a purge on either host scrubs the entire corpus — you don't need to do it twice.

How long memories live anyway

Even without manual purging, plan and interaction rows expire automatically via a background sweep:

The sweep runs daily per company and is silent — you won't see it in Agent Decisions. If you need to verify it ran, check the server logs for MemoryRetentionService.

🔧 Troubleshooting

«I approved an action but nothing happened.»

Check the pill: if it turned ⚠ failed, hover for the validation error. If it stays ⏸ pending, the backend didn't receive your click — refresh the page and try again. If the pending window has expired, the action is gone (auto-rejected); re-ask the agent.

«The observer hasn't ticked since yesterday.»

Open Observer Setup and look at Last run / Next run. If Enabled is off, turn it on. If Last error is populated, read the error: it is usually a missing configuration (no CFO thresholds, no completed job in 48h) rather than a crash.

«Telegram approval doesn't work.»

Open the Telegram Setup page and re-run Install webhook. Then click Test connection — the bot should reply with a small JSON blob. If the test fails, the bot token is wrong or the chat id was never /start'd.

«My 2FA code is rejected.»

Codes are time-based with a 30-second rotation and a 1-step grace window. If your phone's clock has drifted more than ~30 seconds from real time, codes fail. Re-sync time on the device and retry. If you still can't log in, ask an ADMIN to reset your 2FA from Admin → Users (not Security Setup — that page is policy-only).

«I got locked out after failed attempts.»

The lockout window is shown on the login screen. Wait it out, or ask an ADMIN to clear the lockout from Admin → Users. (The thresholds themselves, e.g. «5 attempts then 15 min lockout», live in Security Setup.)

«The AI replies look confused / empty.»

Open AI Setup and click Test on the current provider. If the test succeeds but chats are weird, try a different model (swap gemini-flash for claude-sonnet, or vice versa). If the test fails, the API key has expired or the provider is down — the cascade will automatically fall through to the next enabled provider.

«I asked the Planner to recalculate and nothing happened.»

As of 2026-04-19 the rerun action runs the scheduler inline — the reply should say something like «Applico. Score 1432 → 1208, OT 40′, unscheduled 0.» with a green ✓ applied pill. If you still see an old-style «I set the job to READY, click Run» reply, you are on a cached PWA shell: hard-reload (Ctrl+Shift+R) or wait for the service worker to pick up the new version. If the pill is ⚠ failed, hover it for the scheduler error.

«My sidebar is missing pages I used to see.»

The sidebar now groups pages into collapsible sections and opens them all collapsed on first load. Click the section header (e.g. 🤖 Agents, Inventory) to expand it. See WMS menu layout for the full mapping.

«Simulations page is empty / SIM badge is missing.»

The Simulations page lists the last N jobs for your tenant. If you see nothing, you simply haven't produced clones yet — run an apply_rebalance, apply_level, or apply_absence from a Planner chat, or just press Calculate Plan from UFCP. The SIM badge appears only on Jobs with an active settings override; canonical plans don't carry it by design.

🔑 Terms & Privacy

The platform is operated under the EU GDPR framework. The full legal texts live at Privacy Policy and Terms of Use. This section is a plain-English summary for day-to-day users.

Consent modal at sign-in

When a new version of the Terms or Privacy Policy is published, at your next desktop sign-in you see a small modal: “We've updated our Terms & Privacy”. Review the two linked documents (they open in a new tab) and click Continue. Your acceptance is recorded with version, UTC timestamp, and IP address on the Users row for audit. Badge-scanner logins skip the modal — operators accept at their next email-based sign-in instead.

What we collect

Where it lives

All operational data is stored in EU data centres (Hetzner, Germany/Finland). LLM API calls for agent reasoning may be routed to US regions when you select US-based providers in Governance settings — this is disclosed at selection time and can be disabled per-tenant.

Your rights

EU/EEA residents have full GDPR rights (access, rectification, erasure, portability, objection, complaint to the Garante). Users in other regions retain equivalent rights under their local regime (UK-GDPR, CCPA, LGPD, revFADP). Access requests are handled via privacy@dressai.info. Tenant ADMINs can also trigger Memory Browser exports directly — see the Memory Browser & GDPR section.

When things change

We bump the version string of the Terms or Privacy Policy on material changes. The consent modal re-appears at the next sign-in so you're never silently bound by a new text.

📖 Glossary

ADMIN
A user with full access to the tenant's setup pages and per-user reset actions.
Agent Chamber
Read-only timeline of agent activity. See above.
Agent Decisions
Structured audit log of every dispatcher action, filterable by persona / action / status / time window. See above.
Autonomous runtime
The background loop that lets agents propose actions without a human chat turn. Gated by AutonomousEnabled and DailyActionBudget in Agent Governance.
Autonomy threshold
The highest impact level the agents may act on without asking. Set in Agent Governance.
AutonomousShadowMode
Governance switch (default off). When on, the autonomous runtime keeps proposing but every proposal lands pending regardless of level — admin reviews and approves by hand. Trust-builder before auto-apply is enabled. See Agent Governance.
autonomous_action
A memory Kind written every time the autonomous runtime dispatches a decision — one-line narrative companion to the structured row that lands in Agent Decisions. Surfaces in the Agent Chamber timeline so the operator gets a readable story of what the agent did while they were away. Shipped 2026-04-19.
CCNL
Italian collective labour contract. Hard-coded limits on OT, rest, and night-shift. The CHRO persona enforces them.
Concern
A finding an observer wrote to memory when a threshold was breached. Surfaces in the Chamber and influences the chat's answers.
Event bus (A#2)
Postgres LISTEN/NOTIFY channel that wakes peer observers sub-second on a high-severity concern. See The Agentic Org for the full protocol.
Impact level
LOW / MEDIUM / HIGH — how much the action could disrupt operations. Decides whether the action is auto-applied or pending.
Observer
A background service that periodically reads memory, checks thresholds, and writes concerns. One per persona.
OPERATOR
A warehouse user with badge + PIN access, no setup rights.
Outcome
The verdict the OutcomeEvaluator writes on each dispatcher row after comparing the plan score before and after the decision. One of positive, neutral, negative, inconclusive. Shown as a coloured pill in Agent Decisions.
Plan score
A numeric summary of how well a computed plan hits the tenant's objectives. Lower = better. The COO observer watches drift over a 14-day window.
SIM badge
Small marker shown next to a Job's status when the Job carries a SettingsOverrideJson. It means the Job is a what-if simulation, not a canonical plan. Autonomy ignores these.
Simulations page
WMS sidebar entry (under Agents) listing recent Jobs with inline rename, status, SIM badge, Open, Delete. See What-if simulations.
Tenant Knowledge
ADMIN page holding the five admin-curated tables that steer the agent: policies (binding MUST rules), preferences (soft SHOULD tilts), exceptions (date-scoped / recurring deviations), patterns (observed empirical truths read as context, not commands) and user attributes (per-operator skills / certifications / notes). Read on every chat turn; honoured by the WMS scheduler during Calculate Plan. See above.
TenantException
A row in Tenant Knowledge that narrows a TargetType (user / global / …) to a recurrence and a date window. user and global exceptions steer the WMS scheduler; other target types are prompt-injection only for v1.
TenantPattern
A row in Tenant Knowledge that captures an observed empirical truth about how the company actually operates — e.g. «PICK saturation runs +20% on days 28-31 of the month». Has a Confidence between 0 and 1; agents read it as context, not as a rule to enforce. The Source field records which observer wrote it. See above.
UserAttribute
A row in Tenant Knowledge attaching structured metadata to a single operator — Kind in (skill / certification / consent / language / note), plus a Key and Value. Makes skills and certifications visible to the agent without extending the core User entity. Not enforced by the scheduler. See above.
Memory Browser
ADMIN page under 🤖 Agents to inspect the per-company agent memory corpus with filters and per-row delete, and to run GDPR export / purge for a specific user. See above.
FeedbackScore
A number in [-1, +1] attached to every memory row. Nudged by admin thumbs-up / thumbs-down on Agent Decisions and by the outcome sweep when it writes a verdict. Used as a fourth term (weight 0.1) when the agent retrieves relevant context on future turns.
TOTP
Time-based one-time password, RFC-6238 — the 6-digit code from your authenticator app.