Open Items Register¶
Owner: El · Last reviewed: 2026-08-17
Purpose, and how this differs from the roadmap¶
This register holds things that must be resolved, verified, or decided — risks, unverified assumptions, security debt, legal questions, and contradictions between documents. Each entry names what it blocks, so nothing gates a client quote silently.
The roadmap holds planned work, sequenced over time. It answers what are we building and when.
| Register | Roadmap | |
|---|---|---|
| A decision not yet made | ✅ | ❌ |
| A fact not yet verified | ✅ | ❌ |
| Security or legal debt | ✅ | ❌ |
| A contradiction between docs | ✅ | ❌ |
| A feature to build | ❌ | ✅ |
| A client deliverable | ❌ | ✅ |
An item leaves this register in one of three ways: it is resolved and closed; it becomes an ADR (a decision was made); or it becomes a roadmap item (it turned out to be build work). It is never deleted silently — closed items move to the Closed Items register with a date, a reason and an outcome.
A Deferred item has not closed. It stays here, with its mitigation and the trigger that ends the deferral — a deferral without a trigger is a decision nobody made.
Scope: ABOS only. The Internal Portal and ContractAR keep their own registers in their own repositories.
Status values: Open · In progress · Blocked · Deferred · Closed
IDs are permanent. Never reuse a number, even after closure.
A. Blocking the Greenhills quote¶
Nothing goes on paper until A1–A3 are answered. OI-001 in particular can turn a fixed-price build into a loss.
| ID | Item | Owner | Status |
|---|---|---|---|
| OI-001 | AroFlo data completeness spike. Pull 90 days of real data. Are there reliable start/finish timestamps per job? Is job type a controlled field or free text? Free text means a classification mapping layer maintained forever. Duration-by-job-type cannot be built without this, and no modelling conjures it. | El | Open |
| OI-002 | Metabase spike. Half day, local Docker, dummy data shaped like the canonical model, 2 GB memory limit. Build a number card, a trend line, a bar by job type. The memory figure sizes the shared host (ADR-0021 §2). | El | Open |
| OI-003 | AGPL review. Embedding open-source Metabase in a closed commercial product routinely triggers legal review. Must be resolved before dashboard revenue is contracted. Not an engineering opinion — get it in writing. | External / legal | Open |
| OI-004 | Clarify what Greenhills means by "approvals." Reporting on their existing approval process, or an assumption that we are building one? Very different quotes. | El | Open |
| OI-005 | Get a number for "live." Client to state the acceptable data lag. 15 minutes is almost certainly enough and costs a fraction of the 2,000 calls/day AroFlo budget. | El | Open |
| OI-006 | Verify the AroFlo reporting gap rather than assert it. "AroFlo has no comprehensive reporting" is exactly the claim a client repeats to their AroFlo rep. The defensible pitch is the cross-system join AroFlo cannot do. | El | Open |
B. Time-sensitive — the window closes¶
| ID | Item | Owner | Status |
|---|---|---|---|
| OI-007 | Greenhills before-state capture. Current invoice volume, manual touch time, rework rate, AroFlo↔Xero reconciliation duration. The window closes the moment anything goes live — after that, every savings claim is an estimate against an estimate. | El | Open |
| OI-008 | Metric definitions signed off by the client before the first run. Redefining "exception" in month four silently invalidates months one to three, and it will not be noticed until a trend looks wrong. | El | Open |
| OI-009 | Minutes-saved multiplier agreed at Blueprint and recorded. "38 hours returned" is a model, not a fact. When challenged, we point at their sign-off, not at our assumption. | El | Open |
C. Blocking provisioning¶
| ID | Item | Owner | Status |
|---|---|---|---|
| OI-012 | Shared host size, with Metabase overhead assumed rather than discovered (ADR-0021 §2, ADR-0023 §5). Depends on OI-002. | El | Blocked (OI-002) |
| OI-014 | Tested restore. Posture is settled (ADR-0026); the restore test is the open item. Restore into a scratch container, diff row counts against source. First restore proven before the first paying client goes live. An untested restore is a hopeful cron job. | El | Open |
| OI-015 | Stand up Bitwarden Teams and populate the shared collection per ADR-0027 — vault passwords, provider root access, MFA recovery codes. No dependency; can be done today. | El + Lachlan | Open |
| OI-036 | AU-resident off-box backup target. Confirm Vultr Object Storage is available in the chosen AU region, with encryption at rest. | El | Open |
| OI-040 | Canonical credential-name list in the repo (names only, never values) so the shared collection can be audited without opening it (ADR-0027 §10). | El | Open |
| OI-042 | Scoped Cloudflare API token for the ADR-0024 dns role — DNS edit on the specific zone only, never the global API key. Stored in Ansible Vault under the core vault ID, not Bitwarden. |
El | Open |
| OI-043 | Build the ansible/ tree per ADR-0024. The directory does not yet exist in this repository; infra/ and inventory/ need reconciling against the decided layout. |
El + Lachlan | Open |
D. Security debt — fix before it propagates¶
Ordered by how expensive each becomes if copied into the client-facing app.
| ID | Item | Owner | Status |
|---|---|---|---|
| OI-016 | ALLOWED_EMAILS is not enforced on the live SSO callback path (Internal Portal). On the portal this is a bug. Replicated into a client-facing app it is one client seeing another client's approvals. Fix before the client review app is designed, so the pattern is not copied. |
El | Open |
| OI-017 | Do not reuse the portal JWT_SECRET for the client review app. Clients are not in the Microsoft 365 tenant; one shared secret across a client-facing surface means a leak crosses tenants. Separate identity, issued per tenant. |
El | Open |
| OI-018 | Approval records: append-only, never updated in place, with a content hash of the exact proposed action. If the payload changes after approval, the approval is void and the item re-queues. Without this, "the client approved it" is unprovable — and that is the sentence said to an insurer. | El | Open |
| OI-019 | Approval expiry fails closed. Pending items need a notification path (email, Teams) and an expiry. On timeout: expire and re-queue. Never auto-approve. | El | Open |
| OI-020 | Metabase patching task in the provisioning playbook (ADR-0023 §8, ADR-0024 §9). Pinned version plus a scheduled bump. Cost scales with dashboard-client count. | El | Open |
| OI-041 | Microsoft 365 break-glass account — deferred, deliberately. Two global admins exist on Octopodia accounts, but both are working identities under the same conditional access policies, so a single bad policy could lock out both. Mitigation, in force now: both admins' MFA recovery codes in Bitwarden, ≥2 MFA methods per admin, and no tightening of conditional access policies until the break-glass account exists. Trigger: first paying client. (ADR-0027 §11) | El | Deferred |
E. Legal and commercial¶
| ID | Item | Owner | Status |
|---|---|---|---|
| OI-021 | Vanity-domain support clause in the service agreement. Accepting client vanity domains (ADR-0022 §5) puts their DNS in our uptime path. The agreement must name the Octopodia address as the supported one, with the vanity name offered as convenience. A liability boundary, not a naming detail. | El | Open |
| OI-022 | "No review, no go" reflected in contract terms and liability caps before client use. The tagline is a commercial commitment, and OI-018 is the evidence artefact that backs it. | El + Lachlan | Open |
| OI-023 | Data hosting region disclosure and consent in all client agreements (ADR-0008). The clause commits us to disclosing a region, not a vendor — which is what keeps provider switching open. | El | Open |
| OI-024 | Bespoke dashboard cards priced with a maintenance component. They break when AroFlo changes a field, and someone has to fix them. Every one given away free is an annuity we pay. | El | Open |
| OI-052 | Price dedicated hosting at its true cost. A dedicated box is not "another VPS". ADR-0030 makes it conditional on moving the control plane to its own host and standing up private networking (OI-046) — both one-off engineering costs that land the first time a client asks. Treat the request as a project, not a plan upgrade. | El + Lachlan | Open |
| OI-037 | Approval-log retention floor disclosed in the service agreement. ADR-0026 sets a floor a client cannot request below. Holding client-adjacent data longer than a client might prefer must be disclosed, not discovered. | El | Open |
| OI-038 | Monthly audit report — scope and price. Built on the approval log. Offering it converts retention from internal policy into a contractual commitment. Becomes a roadmap item once scoped. | El + Lachlan | Open |
| OI-039 | Scope boundary of "no review, no go" in client-facing language. The commitment covers AI-generated actions; deterministic automation (scheduled syncs, provisioning) runs unapproved. A client could reasonably read the tagline as covering all automation, which would make the product unusable and the commitment unmeetable. Must be explicit in the agreement, not implied. | El + Lachlan | Open |
F. Cross-repository corrections¶
| ID | Item | Owner | Status |
|---|---|---|---|
| OI-044 | octopodia-portal/docs/business/INFRASTRUCTURE.md says "EU by default." Directly contradicts ADR-0008. This document feeds client agreement language, so the contradiction has commercial consequences. Also carries a stale Trigger.dev reference and a multi-tenant connector claim inconsistent with ADR-0023. |
El | Open |
| OI-045 | octopodia-portal/docs/products/ai-employee/VPS-SETUP.md specifies Hetzner and EU regions, manual provisioning, and snapshot "golden image" cloning — all superseded by ADR-0008, ADR-0021 and ADR-0024. Correct or clearly mark as historical. |
El | Open |
G. Decisions still to make¶
| ID | Item | Owner | Status |
|---|---|---|---|
| OI-029 | Approval granularity: per action or per batch. Per-action is defensible and will exhaust a client receiving forty invoices a day. | El + Lachlan | Open |
| OI-030 | Does Greenhills get Metabase logins, or only curated views? Shapes how defensively the serving layer is modelled. Current lean: curated, since interactive embedding is Pro-tier and bills per signed-in viewer. | El | Open |
| OI-031 | Live numbers or a monthly snapshot for Octopodia's own value reporting? | El + Lachlan | Open |
| OI-032 | Ratify the reporting and dashboard ADR (docs/adr/DRAFT-reporting-and-dashboards.md). Blocked on OI-001, OI-002, OI-003. |
El + Lachlan | Blocked |
H. Watch items — deliberately not now¶
| ID | Item | Revisit when | Status |
|---|---|---|---|
| OI-033 | DuckDB-WASM + Parquet for the native headline layer. No backend, no JVM, no AGPL question, no per-tenant CVE patching. Costs: the whole file lands in the browser so row-level access control is impossible; snapshot not stream; charting becomes our build. | After Greenhills ships. Serving views export to Parquet either way. | Watch |
| OI-034 | Control-plane migration to its own host. Triggers per ADR-0025 §3. | On trigger | Watch |
| OI-035 | Interactive Metabase embedding (Pro tier). Unlocks client self-serve querying and white labelling; bills per signed-in viewer. | If self-serve becomes a sales blocker | Watch |
| OI-046 | Tailscale / private networking. Deferred per ADR-0021 §6. | A second host — this is now the binding trigger (ADR-0030): brain-to-registry becomes a real network hop and must not cross the public internet. Also: a third person needing shell access, or the public SSH port ceasing to be acceptable. | Watch |
| OI-047 | Tenant migration runbook — shared host → dedicated host. Not yet written. Sequence: lower {tenant}.app TTL to 60s a day ahead → provision tenant stack on the new box → restore from per-tenant dump (ADR-0026) → verify → stop writes on old → final incremental sync → move the CNAME → hold the old stack cold for a rollback window → restore TTL. Caddy on the new host must know the hostname before the CNAME moves, or the certificate request fails. Write it before the first migration, not during. |
El | Open |
| OI-048 | Monitoring: what runs behind console.octopodia.com.au/health. A core_stack decision, deliberately deferred. The constraint is already fixed: on-box monitoring covers container state and metrics, but uptime checking must be external — an on-box monitor cannot report that the box is down. Sentry already covers error alerting. |
El + Lachlan | Open |
| OI-049 | Brain statelessness must be enforced, not assumed. ADR-0030 makes replicas safe only while the brain holds nothing that outlives a request — in particular LangGraph checkpoints must persist to the tenant's Postgres, never local disk or memory. Verify when the brain is built; a violation is invisible on one host and corrupting on two. | El | Open |
| OI-050 | Reconciliation pass to report brain version per host. Version skew across hosts is behaviour that differs by which box a tenant sits on, with nothing appearing broken (ADR-0030). Needs to be visible, not inferred. | El | Open |
| OI-051 | Split the core_stack role by scope. ADR-0030 divides it into per-host components (Caddy, brain replica) and global ones (registry, Console). The current single stub role encodes the old assumption. |
El + Lachlan | Open |
Closed items live in the Closed Items register.