# Situations rebuild — operator talking points + gap list (2026-07-25)

> **Status: INTAKE, not yet a kickoff.** These are the operator's own orders from
> the 2026-07-25 session, captured verbatim in substance so they survive the
> conversation. One fork is unresolved (mockup vs straight-to-build) and several
> design points below are still OPEN — this file becomes the kickoff once he
> rules. Nothing here is built.
>
> Standing frame: `KICKOFF-PROMPT.md` laws, `docs/DECISIONS.md` (Agent —
> Situations & instructions), `design/tokens.md`.

## Why this exists

Operator verdict on every prior Situations mockup round: *"every mockup of
situations didn't incorporate and improve its design but inherit it."* The
screen has accumulated through scope-4, -7, -10 and -11 and is now
`Situations.tsx` at **1753 lines / 17 components in one file** plus **631 lines**
of bespoke `cm-sit__*` CSS. He asked for the code, CSS and HTML to be
refactored as part of this, not after it.

## The operator's orders (2026-07-25)

1. **One big field per header.** Each of the fixed headings gets ONE field that
   covers everything under it. Example given: *Goal* today holds four separate
   fields (Its goal · How it opens chat · Always reply · Following a change of
   topic) — it becomes one field, and sub-structure lives **inside** it as
   **markdown sub-headings**.
2. **One Edit button for the whole page.** Not one per sub-heading — *"muy bad
   UX"*. One edit affordance puts every field on the tab into edit mode; one
   save.
3. **Knowledge is the special case — KB rows, not a UI environment.** Under the
   *Knowledge* header sit KB rows only. Reference: ManyChat (three screenshots
   supplied — list / view / edit).
   - Row shows the KB's heading + last-updated; a `⋯` menu with **view, edit,
     delete**; clicking the row also opens the view.
   - **Text KB only** — do NOT build the "Add link" / "Add text" type split.
   - Edit mode: title field (*"What's this about?"*), Content textarea,
     Cancel / Delete / Save.
   - In **Comment replies** and **Moderation**, the Knowledge header must show
     **KB rows too** — not "learned examples".
4. **~~Remove the situation strip~~ — CORRECTED BY THE OPERATOR 2026-07-25.**
   The blue `Conversations WHATSAPP · INSTAGRAM · FACEBOOK / …` band **STAYS**,
   and so does the rest of the bar furniture. His words: *"I didn't demand the
   blue strip to be removed and stripping bar furniture. just situation and its
   separator."* Only the tab-bar `SITUATIONS` label + separator go (order 7).
   **Consequence: gap 1 below is void — "See the exact prompt" keeps its home.**
5. **Parked for Flows: delete the UI.** Save the parked content to a markdown
   file in the repo and remove the box from the deployed site.
6. **Per-channel additions, once per header.** One big field per header ⇒ one
   per-channel addition per header. **Knowledge can be per-channel too.** The
   current per-channel selector is rejected: *"the per-channel selector/ui is
   not good, I don't like the pills."*
7. **Remove the `SITUATIONS` divider label** in the tab bar.
8. **Remove the "add an instruction under [heading]" form.** With one field per
   header, a custom instruction is just text typed into that header's field.
9. **The replay-gate toggle moves to Settings** — and its copy is ambiguous.
   (Pros/cons delivered in-session; see OPEN 4 below.)
10. **No read-only rows — and the answer is EDITABLE** (operator, clarified
    2026-07-25): *"some of if not all the fixed blocks in situation was
    genuinely opened to be edited. I have not enforced any knowledge to be fixed
    and not edited."* So every `FIXED` block becomes **editable prose inside its
    heading's field**. Nothing is "fixed by design" because he never asked for
    that — the fixed-ness was our invention.
    `AUTOMATIC` values (Who they are · Returning contact · After hours · Lead
    progress) **leave Situations** — but they are **not hidden forever**: they
    resurface under the **Automation section, on the agent node** (scope-5).
    Relocated, not deleted.
11. **Remove the changed-mark family** — `EDITED · SEE CHANGE` and anything of
    its type. Orchestrator reading, to be confirmed: this also covers the
    `Default | Now` diff panel and the green changed-dot on tabs. **"Undo my
    change" is kept** — a real action, not a transient marker.
12. **Remove the stepper/arrows artefact** seen at the end of the tab row.

### Standing law he stated while giving order 11

> *"Assume anything added or such (component, UI, behaviour) will most likely be
> permanent until a developer-dependent action is taken on it. This is not a fun
> game playing field."*

Nothing transitional, nothing "temporary", nothing that is expected to age out
on its own. Ledgered in `docs/DECISIONS.md` (2026-07-25).

## Gaps the orchestrator raised (he asked "anything I missed?")

1. ~~"See the exact prompt" dies with the strip~~ **VOID** — the strip stays
   (order 4 as corrected). The button keeps its home. His only note on it is
   styling: *"See the exact prompt" muted, **Edit** more dominant* — the two
   currently sit together but look unrelatedly different.
2. ~~Rails become deletable~~ **RULED 2026-07-25: no special treatment.** He
   rejected the locked block outright (see mockup change 5) — no red overlay, no
   separate edit button, no "always on" label, no second nesting level. Rails are
   ordinary editable prose under Guardrails, because he never asked for anything
   to be non-editable (order 10 as clarified). The `NON_REMOVABLE_SECTION_IDS`
   machinery in `prompt-seed.ts:285` is our invention and goes.
3. **This is a one-way data migration that changes the live prompt.** Collapsing
   per-module overrides + custom instructions + channel appends into one field
   per header destroys per-module identity, so splice order changes and **the
   goldens WILL move**. Every prior Situations package gated on
   "goldens byte-identical"; this one cannot. **Needs the operator's explicit
   sign-off** because the live bot's prompt text changes.
4. **Replay gate — the pros/cons he asked for.** What it does
   (`situations.controller.ts:207-258`): per situation, on save it refuses with
   409 and returns an estimate (labelled-turn count + $), and on confirmation
   re-runs the candidate config over that labelled set, refusing if the set
   exceeds `MAX_LABELS` or if any turn previously graded **right** now decides
   differently.
   - *On*: an edit that breaks an already-correct decision cannot reach the live
     bot; cost shown before charging.
   - *Off*: saves are instant and free.
   - *The decider*: it charges real LLM money per gated save, **and** base-text
     edits bypass it entirely (`patchAgentConfig` saves unconditionally —
     boarded at `scope-board.md:203-207`). One-big-field makes every edit
     base-text-shaped, so the gate would protect **almost nothing while still
     looking like protection**.
   - **Recommendation:** do not move a broken automatic gate into Settings. Kill
     the automatic gate; add a manual *"Test this change against my labelled
     examples"* button beside Save that shows the cost and runs only on click.
     Respects the never-spend-unapproved law and stops the screen lying.
5. **One page-wide edit mode makes an existing state-loss bug much worse.** The
   editor remounts and discards local edits on any refetch (`editorKey`,
   `Situations.tsx:293`). Losing one textarea is annoying; losing a page of
   edits is not. Needs a dirty-guard.
6. **Empty headers.** Comment replies has 5 modules, Moderation 3 (each one fewer
   since the `examples` module was deleted — gap 7), mapped across 5 fixed
   headings — so more come out empty than before. Recommendation: show the header with
   an empty field so he can type into it. **OPEN.**
7. **Learned examples must STOP FEEDING THE PROMPT — RULED 2026-07-25; LANDED
   AND DEPLOYED (commit `1091268`).** His words, a correction of a decision we
   made without him: *"learned examples should not feed the prompt, that is a
   decision I didn't approve, I removed it specifically so it doesn't also feed
   the prompt."* They were spliced in at `situations.controller.ts:271-273`
   (enriching the `examples` module, which the engine then assembled).
   - **Done:** the whole path is deleted, not merely disconnected — the `examples`
     module type and its registry compile, `formatExamplesBlock`,
     `SystemPromptOptions.examples`, `ExamplesService`, the `skipExamples` replay
     flag and the dead `agentReview.exampleLimit` cap. It cannot be rewired by
     accident.
   - **Untouched:** `decision_labels`, the Activity surfaces that manage the
     right/wrong marks, and replay (which gets simpler — with no few-shot block
     there is no labelled answer to suppress).
   - **The goldens did NOT move**, contrary to the expectation recorded here.
     Every scope-4 snapshot assembles with no examples fed, so the case that
     mattered was never pinned: re-splicing graded text into the moderation prompt
     leaves all 45 golden tests green (verified by mutation). The real pin is
     `packages/shared/src/agent/graded-examples-never-in-prompt.test.ts`.
8. ~~The `Website` channel inconsistency~~ **RESOLVED 2026-07-25: "website will
   be a channel too."** Four channels, Website included, everywhere — including
   per-channel Knowledge, which he also approved explicitly.
9. **Edit-mode scope**: one Edit per **tab** (all prose fields on that tab, one
   save), with KB rows editing independently. **Confirmed in effect** by his
   mockup review — he approved the sticky save bar and asked only that its
   caption "One save for everything on this tab." be removed.

## Mockup round 1 — operator reaction (2026-07-25)

Mockup: `plans/rethink/situations-rebuild-mockup-annotations.md` (artifact URL in
the session log). His verdicts:

**Approved:** the sticky save bar. Per-channel Knowledge. Website as a channel.

**Rejected:** the one-line note beside each heading. "Read all of it" (do not add
it anywhere). The commentary under headings ("Who the bot is", "What it is trying
to do", "How it sounds", …) — delete it.

**Changes required:**
1. **Global tab keeps its distinctive styling.** Removing the word "Situations"
   from the tab bar was never a request to flatten Global's design — it must keep
   the treatment it has today, not render plain like the situation tabs.
2. **KB row `⋯` menu reads exactly "View", "Edit", "Delete"**, each with an icon.
   (Round 1 used "Read it / Change it / Delete it".)
3. **Viewing a KB opens a side panel, ManyChat-style — it must NOT replace the
   page headers.** On a narrow screen the panel becomes effectively full-screen,
   sized to the window width.
4. **Per-channel addition needs a seamless treatment.** Drop the "Added on one
   channel only" header entirely when nothing is added, and even when something
   IS added he dislikes that header — find something more seamless.
5. **Guardrails: no red overlay, no separate edit button, no "Safety limits ·
   always on" label, and no second level of nesting.** His question stands as the
   design rule: *"if there is a guardrail or a limit it will be under guardrails
   why did you add two levels of separation that is not needed?"* One field under
   Guardrails, sharing the page's single Edit. (This supersedes gap 2 below —
   rails are not a locked block.)
6. **Only the Knowledge boxes on Conversations look right.** The others carry
   very obvious black borders — bad.
7. Save bar: **remove the caption** "One save for everything on this tab."
8. Knowledge: the add button reads **"Add Knowledge"**, not "Add something the
   bot should know".
9. **"See the exact prompt" and "Edit" sit together but look unrelated** — make
   *See the exact prompt* muted and *Edit* the more dominant of the two.
10. **Review the seeded KB content** — he suspects those titles/dates/counts are
    only reformatted text rather than real documents. Check what the live 9
    `KnowledgeDocument` rows actually contain before presenting them as KB.

## Two bugs that this rebuild DELETES rather than fixes

Noted so nobody spends a seat fixing them separately:
- **Stale collapsed preview** — `CompanyBlock` previews `company.houseRules`
  (`Situations.tsx:1157`) while editing writes `company.fields` (`:426`), so a
  saved edit shows the old text. `FlowBlock` has the same shape (`:1199`).
- **One-way re-parking** — the unrestore link needs `m.parked`
  (`Situations.tsx:727`) which is computed from the *saved* config
  (`situations.ts:610`), so restore→save removes the link and the row.
  (This was the boarded agent-scope-11 gate follow-up.)

Also dies with the rebuild: the dead `struck` vocabulary ("Replaced here",
"Contributes nothing", crossed-out gutters) that legacy data can still surface.

## Facts established this session (don't re-derive)

- **Five headings, not seven.** `packages/shared/src/agent/instruction-headings.ts:38`
  → `["Role","Goal","Tone","Knowledge","Guardrails"]`, matching
  `docs/DECISIONS.md:96-99`. **`plans/rethink/agent-scope-10-kickoff.md:92-94`
  and `plans/rethink/scope-board.md:131` both still say seven — stale, flagged
  to the operator, not silently reconciled.**
- **Knowledge already has a real model** — `KnowledgeDocument`
  (`packages/db/prisma/schema.prisma:1206`): `title`, `content`, `tags`,
  `enabled`, `updatedAt`. KB rows need **no new table**; per-channel is one
  additive `channels String[]`. It also carries `kind`/`category`/`data` for
  structured docs (`area`/`process`/`fees`/`faq`, `:1210-1212`) — the live 9
  documents must be inspected before anything touches those kinds.
- **Only two real field editors exist** (`content-editors.tsx`:
  `BaseSectionField`, `FieldListEditor`); everything else is a bare inline
  control. **Four field kinds render with no primitive at all**: the
  channel-variant textarea has no class (`Situations.tsx:1020`, styling
  hand-duplicated in `situations.css:382-395`), the "Applies to" chips are
  native checkboxes (`:1545`), the replay-gate is a bare checkbox (`:763`).
- **`Input` / `Field` / `Chip` primitives already exist**
  (`apps/web/src/components/ui/index.ts:15-19`) and are used **nowhere** on this
  screen. The rebuild uses them; `cm-select`/`cm-input`/`cm-field` proper are
  built in channels-scope-5 Stage E and swept after.
- **Field names are free text injected verbatim as prompt headings**
  (`content-editors.tsx:234` seeds `"NEW FIELD"`, `settings.ts:205` splices it)
  — no validation, no dedupe, no delete confirm, rows keyed by array index.
- **Three different metaphors for "make this stop applying"** today: seeded
  section (Removed sentinel + Restore + Undo), custom instruction (bare Remove,
  no confirm), parked module (Restore / Move back). One gesture is wanted.
- Custom instructions are **removable but not disableable** — no `disabled`
  flag anywhere in the model, schema or UI.

## Status

**CONSUMED 2026-07-25 → `plans/rethink/agent-scope-13-kickoff.md`.** Round 2 was
delivered and reacted to; its BINDING sheet is
`situations-rebuild-mockup-annotations.md` and its source is
`situations-rebuild-mockup-round-2.html`. Every fork that blocked a kickoff is
closed: strip stays, rails are ordinary prose, everything is editable, Website is
a channel, per-channel Knowledge approved, examples leave the prompt, automatic
values relocate to the agent node, and on 2026-07-25 the operator took all
orchestrator recommendations on the three remaining mockup rulings and signed off
that the goldens move. This file is now history — build from the kickoff.

**The operator granted planning-file authority** (2026-07-25): *"the planning
files you have authority to rectify."* Stale plan/board wording may be corrected
directly rather than surfaced — which closes the standing five-vs-seven-headings
conflict (code + DECISIONS say five; `agent-scope-10-kickoff.md:92-94` and
`scope-board.md:131` are simply wrong and should be fixed).

**Both former open items are closed** (2026-07-25): the goldens moving is signed
off, and Global keeps its tab — it ships with five empty heading fields because
`prompt-seed.ts` seeds nothing for it. What text belongs on Global is the
operator's to write, not a build blocker. Note that examples leaving the prompt
did NOT move the goldens (gap 7) — the pin never covered that case.
