Closed Items Register¶
Owner: El · Companion to: Open Items
Items are never deleted from the open register. They move here with a date, an outcome, and where the decision now lives.
Why keep this. Two reasons, both practical. When a client or an auditor asks in eighteen months why a decision went the way it did, the answer should be a record rather than a memory. And when an item resurfaces, as they do, this stops it being re-litigated from scratch by whoever forgot it was already settled.
IDs are permanent and never reused, including after closure.
How items close¶
| Reason | Meaning |
|---|---|
| Decided | A decision was made. It now lives in an ADR, and that ADR is the authority, not this row. |
| Resolved | The gap was closed by doing the work. |
| Verified | The question was one of fact, and the fact was checked. |
| Re-scoped | The item was real but belonged elsewhere. The successor item is named. |
| Void | The premise was wrong. The problem did not exist. |
An item that is deferred has not closed. Deferred items stay on the open register with a trigger, because a deferral without a trigger is a decision nobody made.
2026-10¶
| ID | Item | Reason | Outcome | Closed |
|---|---|---|---|---|
| OI-091 | The Junior's Gmail search re-fetches mail the client un-labelled, and is capped at 50 | Resolved | Paged ID listing, sorted IDs skipped before any full fetch (stage 6, 10 October 2026). The search now excludes all three Assistant labels, so only unlabelled inbox mail since go-live is listed, every page (IDs only). The shared sub-workflow Junior: what to fetch drops IDs already sorted in the sort log and returns at most 50 for the full fetch, newest first; the rest are listed again next poll. An email the client un-labelled costs one ID lookup a poll, never a full fetch, and can no longer crowd out new mail. Chosen over a time window from the last completed poll, which would lose emails whose labelling failed (they are not in the sort log) once they fell outside the window, and needs completion bookkeeping. Pending retries now count attempts in the sort log. Junior page |
2026-10-10 |
| OI-094 | n8n keeps email content in its execution history | Decided | Successful runs are not saved. Failed runs and manual runs are saved and pruned after 7 days. The same on every host, lite-dev included (El). A saved execution holds the subject and the cleaned body sent to the AI, so not saving successful runs is what makes we keep a record of what was sorted, never what the email said true; failed runs are kept briefly because a fault cannot be diagnosed without them, and the proposal says so. Set in the n8n role (n8n_save_on_success, n8n_save_on_error, n8n_save_manual, n8n_prune, n8n_max_age_hours), checked against n8n 2.42.4. An operational setting rather than an architectural decision, so recorded in the role, the runbook and the Junior product page, not in an ADR. n8n Insights still counts unsaved runs (OI-089). |
2026-10-10 |
| OI-093 | Gmail credential's Allowed HTTP Request Domains on lite-dev unconfirmed |
Verified | El checked the credential in the n8n UI: Specific, gmail.googleapis.com. The runbook's earlier None was wrong, and the runbook now states the correct setting. Since stage 4b every Gmail call is an HTTP Request node, so this is the setting that stops the token being sent anywhere else. |
2026-10-10 |
| OI-092 | Known senders: per mailbox or shared across a business's mailboxes | Decided | Per mailbox, for now. Each known_senders row carries its mailbox, and the sorter looks senders up only within the mailbox being sorted, as built in stage 4b. Simpler to explain and to undo. Sharing across a business's mailboxes is a later option, taken only if a client asks: a one-node change in the sorter. A product setting rather than an architectural decision, so it is recorded on the Junior product page, not in an ADR. |
2026-10-10 |
2026-08¶
| ID | Item | Reason | Outcome | Closed |
|---|---|---|---|---|
| OI-019 | Approval expiry fails closed | Void | Superseded by the same reasoning that closed OI-080. Expiry was solving two problems badly, and once queue ageing existed they separated: ageing handles "nobody has looked at it" and draft_staleness handles "the draft no longer fits". There is no expiry to fail closed, because approvals do not expire. The "never auto-approve" commitment survives intact and is stronger for it: nothing times out into an action. The notification path this item also asked for is now ADR-0034. |
2026-08-19 |
| OI-079 | Reopening a closed work item was undefined | Decided | A reopen is a new work item that inherits history. Fresh assessment, fresh config, fresh flags, and the only thing carried forward is the conversation. That framing removed the field-by-field reasoning: if you would ask it of a new item, ask it again on reopen. status returns to assessing, attention_reason clears (its history lives on the append-only decision rows), and versions are restamped to current, which is not an exception to ADR-0006's pinning rule because pinning holds for the life of a work item and a reopen starts a new life. Two fields added: first_closed_at, set once and never cleared, without which a reopened item cannot be told from one that never closed and reporting double-counts, and reopen_count. Recorded in flow/approve.md. |
2026-08-19 |
| OI-074 | The Draft prompt was not designed | Resolved | Written as docs/products/email-triage/prompts/draft.md. The design turns on accuracy over voice, and on a mechanism rather than an instruction: a KNOWN and NOT KNOWN block, where NOT KNOWN is generated from what Resolve failed to find and what the job record leaves null. Without it a model asked about a Thursday job writes "our technician will be there Thursday morning", because that is what such an email usually contains. Also settled: the model returns body text only (subject and recipients from the connector, signature and HTML from the tenant template), retrieval uses approved drafts only with the edited version stored where a human changed it, an empty example set is expected on day one rather than a bug, and the mandatory regenerate reason goes in verbatim so attempt two differs from attempt one. |
2026-08-19 |
| OI-080 | Approval expiry undefined | Void | The premise was wrong. "Expire into what?" had no honest answer because expiry was solving two problems badly. Once queue ageing existed, they separated cleanly: ageing handles "nobody has looked at it", lifting the item until it is at the top, and draft_staleness handles "the draft no longer fits", sending it back to the brain to be regenerated with the delay as a fact. That is the same mechanism as a chase, triggered by time rather than by the customer. Nothing expires into a dead-end state, and nothing auto-approves. One config value replaced a status nobody could name. |
2026-08-19 |
| OI-075 | Prompt principles living under email triage | Resolved | Lifted to docs/architecture/prompts.md immediately rather than deferred. That page now holds the nine-section anatomy, the cache boundary, versioning, the escape-hatch requirement and the classification-versus-generation split. The product page keeps only its inventory and what is injected from tenant config. |
2026-08-18 |
| OI-046 | Tailscale, deferred as a watch item | Decided | ADR-0031: adopted from the start, and the public SSH port is closed. The deferral in ADR-0021 §6 rested on the premise that adoption was new work. It was not: Tailscale was already in daily use across existing Octopodia infrastructure, so the marginal cost was small while the deferral left an SSH port exposed to the internet permanently. Retrofitting later would have meant re-running hardening with different firewall assumptions on a host already carrying client data. Follow-ups tracked as OI-056, OI-057, OI-058. | 2026-08-18 |
| OI-010 | Documentation corrections before the docs site publishes | Re-scoped | The stale documents (INFRASTRUCTURE.md, VPS-SETUP.md) live in octopodia-portal, not this repository. Successors: OI-044, OI-045. |
2026-08-17 |
| OI-011 | Vultr region, Sydney or Melbourne | Void | Never open. Melbourne was already settled in the ADR now superseded by ADR-0021. Raised from an incomplete reading of the repo rather than from an actual gap. | 2026-08-17 |
| OI-013 | Ansible repo layout and tenant inventory structure | Decided | ADR-0024: tenant-as-inventory-host, static inventory in git, registry pre-flight gate. Implementation tracked as OI-043. | 2026-08-17 |
| OI-025 | Multi-tenant connector conflict | Resolved | AGENTS.md said "n8n project per tenant", contradicting the licence reasoning for one instance per tenant. ADR-0023 §4 restates it, and AGENTS.md was corrected to match. The ADR was authoritative, not the summary. |
2026-08-17 |
| OI-026 | ADR-0013 double-booking | Void | Not present in this repository. ADR-0013 is tenant modes, uniquely. The collision existed in older notes rather than in the repo. | 2026-08-17 |
| OI-027 | Two ADR series, four-digit versus three-digit | Verified | Deliberate. ABOS uses four-digit, the Internal Portal uses three-digit. Not drift. Cross-references must name the repository, since a bare number is ambiguous across the two. | 2026-08-17 |
| OI-028 | "EU by default" in INFRASTRUCTURE.md |
Re-scoped | Belongs to octopodia-portal. Successor: OI-044. Retained as a distinct entry because it has commercial consequences: that document feeds client agreement language. |
2026-08-17 |