# Workflow

Every task follows the same cycle. Do not skip steps, do not reorder them.

## 0. Does this need the full cycle?

**Plan mode is required for every change to application code**, however small it looks.

It is **not** required for:

- answering a question, explaining code, reading;
- documentation work (`docs/`, `CLAUDE.md`, `CLAUDE.local.md`);
- a change the developer has already specified precisely enough to be the plan itself;
- mechanical, zero-decision edits (a typo, a rename he asked for by name).

When in doubt, plan. Skipping the plan is a decision to be stated out loud, not assumed silently.

Whatever the path, before starting: **ask if there is a convention you do not know yet.** Conventions arriving
mid-task mean rework.

## 1. Planning (plan mode)

Every task that needs it starts in **plan mode**. No file is modified before the plan is approved.

The plan must contain — and nothing more, it has to be readable in under a minute:

- **Task** — the problem to solve, not the solution.
- **Solution** — the approach with its key steps.
- **Acceptance criteria** — how we validate that it is done.

Break the plan into **phases** only when the task is large enough to justify it.

The plan is written to `docs/plans/<slug>.md` as a **living document**: it is updated as implementation
progresses so the current state is always visible. See [plans/README.md](plans/README.md).

## 2. Implementation (auto mode)

After the plan is approved, implementation runs in auto mode.

- **Do not write documentation during implementation.** The concept may still change; maintaining docs
  mid-flight only costs time.
- Keep to the plan. If reality forces a deviation, update the plan file and say so.
- **Do not run Encore.** The developer keeps `npm run encore dev watch` running. Ask him to restart it only
  when it is actually required — a changed `webpack.config.js` or a new entry point. See
  [DEVELOPMENT.md](DEVELOPMENT.md#assets).
- **An env change touches two files.** A new constant goes into `env.php` *and* `env.example.php`, and has to
  be flagged explicitly to the developer — `env.php` does not exist in Git, so a constant that is not called
  out is a constant that is missing on production.

## 3. Phase review

**Stop after every phase.** Hand over a summary of what to review, **ten lines at most**. A category with
nothing in it is left out, not written out as "nothing here".

- which files changed and why,
- what specifically needs a human eye,
- **what could not be verified and why.** Say it explicitly, do not leave it implied. Most of it is
  measurable — [VERIFICATION.md](VERIFICATION.md) lists what can be checked here and what genuinely needs the
  developer's eyes. "Could not verify" is only an honest answer for the last section of that document.
- **what you are least sure about** — at most three, one line each, ranked. Not what could not be checked:
  what *was* checked and might still be wrong. A judgement call, an assumption about what he meant, a case
  the code now handles differently and probably should. Those are what a review actually catches.

Whenever a change makes a **dormant state reachable**, review everything written for that state — it has never
rendered, so it has never been tested, and it will be wrong. Ask what else keys off the thing being fixed.

Whenever the change touches URL structure, **crawl the site link by link before and after** and compare the
non-200 responses. It is cheap, it covers every generated URL rather than the three you thought of, and it is
the only way to see 404s at all.

Whenever the change touches the database schema, say so in the review summary and name the migration. A
schema change the developer does not know about is a broken deploy.

**Run the gates the phase actually needs** and report the result — see [Which gates run](#which-gates-run). A
defect the tests uncover goes into the review summary as its own item; it is the developer's call whether it
is fixed in this task or a later one.

No progress report, no essay.

## 4. Phase commit

**The review is where the phase actually gets finished.** Expect it to come back with changes — sizes,
spacing, wording, behaviour — and expect several rounds of them. That is the normal path, not a sign the phase
was wrong.

- **Do not commit before the review.** A phase is committed once the developer has looked at it and has no
  further changes.
- Each round of changes is its own small commit. If a round only corrects the previous one (same detail, new
  value), `--amend` it instead of stacking commits.
- **`web/build/` stays out of phase commits.** A dev build would replace the committed production build with
  unversioned, unminified files — hundreds of thousands of lines, and a live-breaking push if it slipped
  through. Keep the dev build in the working tree and close the task with a single production
  `Build assets (production)` commit. See [COMMIT.md](COMMIT.md).

Then commit. See [COMMIT.md](COMMIT.md).

## 5. Closing the task

After the implementation is complete the developer reviews the code and either approves it or requests changes.

Once approved:

1. **Update documentation**
   - run `./bin/wiki-stale` and refresh every page it reports, then set their `verified:` line to the new
     `HEAD` — see [DOCUMENTATION.md](DOCUMENTATION.md#2-llm-wiki--docswiki),
   - delete the plan from `docs/plans/`,
   - write an ADR for every decision that was made, if any.
2. **Discuss the lessons of the session** and adjust this workflow and the documentation accordingly.
3. **Commit the documentation** (separate commit from the implementation).
4. **Production asset build** — if `resources/` changed, run `npm run encore production` and commit
   `web/build/`. The server has no Node, so a dev build must never be pushed. See [COMMIT.md](COMMIT.md).
5. **Run the unit tests. Mandatory before every push, no exceptions** — see [TESTING.md](TESTING.md). The
   `pre-push` hook runs them too, but only in a clone where `bin/install-hooks` was run.
6. **Push.**
7. **Hand over the two closing texts** (see below).

## 6. The two closing texts

After the push, write both of these into the chat — not into a file.

### Deployment steps

What the developer has to do on the server for *this* task, in order, with the actual commands. Only what is
really needed: `git pull`, `./yii migrate` if there is a new migration, `composer install` if
`composer.lock` changed, a new `env.php` constant, a cache flush, a search index rebuild, a new cron entry, a
manual data step. If nothing beyond `git pull` is needed, say exactly that.

### Summary for the client

A short message the developer can forward to Andris as-is. Same terse register as everything else, but
**written for a non-technical reader**: what a visitor to the site will notice, and what it means for them.
No framework, file, class or column names, no explanation of the cause, no numbers of files changed. One
line per item, in the order of Andris's own list, referencing his numbering where he used it.

## Which gates run

**A gate that cannot see the change proves nothing and costs minutes.** Running the suite on a documentation
change is not caution, it is the developer waiting.

| What changed | What runs |
|---|---|
| `docs/`, `*.md`, `CLAUDE.md` only | nothing |
| `resources/` | the developer's own `encore dev watch`; the production build once, at task close |
| PHP inside the tested surface | `composer test` |
| PHP outside it | nothing automatic — say so in the review instead of implying coverage |
| anything, before a push | `composer test`, no exception — the `pre-push` hook enforces it |

The tested surface is the curated `<source>` allowlist in
[`phpunit.xml.dist`](../phpunit.xml.dist), listed in [TESTING.md](TESTING.md#the-tested-surface). It is
fourteen files: **a green suite says nothing about the several hundred others.** Name that in the review
rather than letting a passing run imply safety.

Picking a *verification* method follows the same principle, one level up — see
[VERIFICATION.md](VERIFICATION.md).

## Weekly reviews

Both are checked before starting new work, and both track their own date at the top of their own document.

- **Documentation** — if it has not been reviewed for more than a week, read through every document and decide
  what should be reorganized, condensed, updated or dropped. Date in [DOCUMENTATION.md](DOCUMENTATION.md).
- **Tests** — if they have not been reviewed for more than a week, look for testable-but-untested code, check
  that the existing tests still describe reality, and delete what has become unnecessary. Date and the full
  procedure in [TESTING.md](TESTING.md).
