# AGENTS.md — how to use these docs

Entry point for AI agents (Claude Code) and humans working on the **Task & Job Description Management** system.

## Canonical hierarchy

1. **`machine/`** — normative facts. Statuses, fields, roles, decisions, open points. If code contradicts these files, the code is wrong (or the files must be updated in the same commit). **Inside `machine/`, `open-points.tsv` owns open-point semantics** (status, what each point blocks): other machine files may reference point IDs but never redefine their effect; on conflict, `open-points.tsv` wins and the other file is fixed in the same commit.
2. **`functional-spec.md`**, **`architecture.md`** and **`routes.md`** — rationale and narrative. Same facts + the *why*.
3. **`.docx` deliverables** (client-facing, in outputs) — generated documents for humans. Never canonical for agents; regenerated from build scripts.

## Read this first, always

- **Two open points block the core**: `C` (missed behaviour) and `E` (cut-offs & timestamps). **Do not build or modify the recurrence engine / Missed evaluation until they are answered** — recommended defaults exist in `machine/open-points.tsv` but are not client-confirmed.
- Everything user-triggered is **event-driven, real time** (Server Action → pg-boss enqueue in the same transaction → worker < 1 s → SSE). **Scheduled jobs are the exception**: recurring-instance generation, Missed evaluation at cut-offs, backups. No polling, no system crontab.
- A task is **complete at `checked`**. `verified` is a random-sample audit, not a required step. `late` is computed at read time, never stored. `missed` is written only by the scheduled evaluation, only for recurring instances.
- **Layering is law**: all business logic lives in `src/services/` (Zod contracts, Drizzle transactions). Server Actions and Route Handlers are thin adapters — **no Drizzle import outside `services/`** (lint-enforced). **Authorization is enforced in the services**; route-group layout guards are display comfort only (a layout wraps neither Server Actions nor route handlers — it is not a security boundary). Other modules never touch our Postgres: they use `/api/v1` or domain events.
- **Never DELETE** business data: archive / deactivate (`archived_at`, `active=false`).
- Notifications: **application code never calls a channel directly**. Enqueue an event; the worker fans out through `NotificationDriver` (in-app/SSE + ntfy today; Mattermost/e-mail/LINE are future drivers behind the same interface).
- Environment is an **air-gapped LAN** (no internet, ever): no external CDNs/fonts, no cloud push, pinned + vendored dependencies, timezone `Asia/Bangkok` everywhere.

## Reading order for a task

| You are about to… | Read first |
|---|---|
| Touch task states / transitions | `machine/lifecycle.json`, then spec §6 |
| Add/modify task fields | `machine/task-fields.tsv`, then spec §5 |
| Touch permissions / assignment | `machine/roles.json` + open point A, then spec §3 |
| Touch recurrence / Missed | **open points C & E first** (`machine/open-points.tsv`), spec §7 |
| Add a notification | `architecture.md` §4 (adapter), `machine/decisions.json` |
| Change infra / add a service | `machine/decisions.json` (check status + switch triggers) |
| Expose data to another system | `architecture.md` §5 (service layer, REST facade, domain events) |
| Add / move / guard a page | `machine/routes.json`, then `routes.md` |

## Conventions

- Decision statuses: `decided` (build on it) · `default` (start with it; switch trigger documented) · `open` (audit / client answer pending).
- Open points keep their stable IDs `A…H` (mapped to client questions Q1–Q11 of functional spec v3).
- Any change to behaviour ⇒ update `machine/` **and** the relevant `.md` in the same commit.
