People
Engineer asks, uploads and submits · Approver also approves documents and escalations · Admin also manages people · Viewer reads only
| name | role | status | joined | revisions | decisions | manage | |
|---|---|---|---|---|---|---|---|
| D. Mandadiacting as | d.mandadi@corinthia.example | admin | active | 10 Sept 2026 | 0 | 0 | |
| R. Haddad | r.haddad@corinthia.example | approver | active | 10 Sept 2026 | 0 | 0 | |
| S. Rahman | s.rahman@corinthia.example | engineer | active | 10 Sept 2026 | 0 | 0 |
suspending someone removes them from the identity switcher but keeps every row they already signed · a role change takes effect on the next request
| still unattributed | count | why |
|---|---|---|
| Questions asked | 19 | /api/ask records no asker — queries has no user column |
| Revisions with no uploader | 7 | uploaded before this layer, or seeded by the CLI |
| Decisions with no decider | 5 | decided before this layer |
old rows are left null rather than back-dated to whoever is acting now — a record that guesses is worse than one that admits the gap
Governance
| policy | what it means today | state | enforced in |
|---|---|---|---|
| Escalation approval required | The agent can only ever reach draft. status='draft' is hard-coded in the insert and is not a value the model can supply, and the agent has no tool that sends anything. | enforced | lib/agent.ts |
| A decision is one-way | Approve and dismiss update only where the row is still a draft, so a second click or a stale tab cannot overwrite a decision someone already made — it returns 409. | enforced | app/api/escalation/[id]/route.ts |
| Only the active revision answers questions | Retrieval filters to active documents before ranking, so a superseded revision stays on file for the record and can never be cited. | enforced | lib/retrieval.ts |
| Document review gate | An upload is indexed as pending and is invisible to retrieval. A person approves it, and only then does it become the revision in force. The CLI can bypass the queue with an explicit --approve flag for bulk seeding. | enforced | lib/documents.ts |
| Supersede is atomic | At approval, marking the old revision superseded and the new one active happen in one transaction, with the row locked FOR UPDATE so two simultaneous approvals cannot both pass. Never two active revisions, never zero. | enforced | lib/documents.ts |
| Answer only from the documents, or refuse | The grounding prompt forbids outside knowledge, requires a citation per claim, and specifies the exact refusal sentence when the excerpts do not cover the question. | enforced | lib/prompts.ts |
| Every question is logged | Question, retrieved chunk ids, answer, model, latency and token counts are written after the stream ends — including when the reader disconnects mid-answer. | enforced | app/api/ask/route.ts |
| Sign-in | Still no authentication: the acting user is an id in a cookie and anyone can switch to anyone. What exists now is attribution — every upload and every decision names a person — and role gates on each write path. A real session provider replaces getCurrentUser() and nothing downstream changes. | not implemented | lib/users.ts |
| Attribution on writes | documents.uploaded_by, documents.approved_by and escalations.decided_by are stamped from the acting user in the same statement as the status change, so a decided row cannot exist without the person who decided it. Rows written before this existed keep a null and render 'not recorded'. | enforced | lib/documents.ts, app/api/escalation/[id]/route.ts |
| Maker-checker on documents | A revision cannot be approved by whoever uploaded it — the uploader is read under the same row lock as the status check and a match is refused 403. No role is exempt: an admin approving their own upload is the case the rule exists to stop. | enforced | lib/documents.ts |
| Role gates on every write | Viewer reads only; engineer uploads and submits; approver and admin decide; admin manages people. Each gate is re-checked server-side in the action or route handler, so hiding a button is a courtesy and never the control. | enforced | lib/users.ts, actions/identity.ts |
| Audit retention | Rows in queries and escalations are never edited or deleted, but nothing expires them either. There is no retention window. | not implemented | — |
| Tenant isolation and rate limiting | No tenant_id column and no request limits. Both are named in the README as the first production additions. | not implemented | — |
these rows are read from the code, not from a settings table — there is nothing to toggle here, and a switch that changed nothing would be worse than no switch at all