---
kind: spec
status: active
source_of_truth: true
---

# Native Kanban and Canonical Task SOT — Canonical Requirements

**Status:** RATIFIED and independently approved for canonical publication under issue [#751](https://git.mosaicstack.dev/mosaicstack/stack/issues/751)
**Date:** 2026-07-14
**Decision owner:** Jason
**Publication owner:** web1 control plane (`mos-claude`; `mosaic-100` acting during Claude quota outage)
**Implementation foundation:** current `mosaicstack/stack` main only
**Implementation hold:** no feature implementation begins until this canon is squash-merged to `main` with terminal-green CI.

## 1. Purpose

Deliver Mosaic Stack's native project/task control plane and thin writable Kanban on one authoritative PostgreSQL model. This document formalizes the ratified source plan; it does not create a parallel design.

Normative terms **MUST**, **MUST NOT**, **SHOULD**, and **MAY** are binding as used here.

## 2. Ratified decisions

| #   | Ratified decision                          | Canonical result                                                                                                                                                                                                                                                                                       |
| --- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| D1  | Foundation                                 | Extend current `mosaicstack/stack` main with its existing Drizzle/PostgreSQL, NestJS Gateway, Next.js, Better Auth, and Valkey/BullMQ conventions. No greenfield service and no Prisma revival.                                                                                                        |
| D2  | Tenant boundary                            | `workspace_id` is the hard tenant boundary from the first migration. Teams are authorization groups inside a workspace, never tenant substitutes.                                                                                                                                                      |
| D3  | Outage authority — Option A with amendment | PostgreSQL is the sole writable SOT and mutations fail closed whenever DB write-health cannot be proven. The amendment permits deployment-specific **recovery posture only**; it does not permit an alternate writer. Human outage notes are attributable post-recovery proposals, never shadow state. |
| D4  | Generated files                            | `TASKS.md`, `mission.json`, and any file export are generated, read-only, non-authoritative, and never import sources. Generate on demand; commit only where repository review policy requires a snapshot.                                                                                             |
| D5  | Status model                               | Task statuses are `backlog`, `ready`, `in_progress`, `blocked`, `in_review`, `done`, `cancelled`. Runtime readiness is orthogonal and computed.                                                                                                                                                        |
| D6  | Coordinator approval                       | Hybrid: manual Project Sub-Orchestrator approval by default; automatic routing only under an explicit, approved, versioned low-risk policy.                                                                                                                                                            |
| D7  | Initial migration scope                    | Project, mission, milestone, task, tags/archive, dependency, assignment, outage proposal, evidence/link, and orchestration state only. Calendar, email, GLPI cache, and personal-brain features remain out of scope.                                                                                   |

## 3. Fixed invariants — every deployment

These are not tier settings and cannot be weakened by deployment configuration.

1. PostgreSQL is the **sole writable source of truth**.
2. The implementation uses Drizzle on current stack main.
3. Kanban and orchestration mutations **fail closed** unless DB write-health is positively proven `healthy`.
4. No failed mutation is redirected to Markdown, JSON, browser storage, Valkey, queue payloads, scratchpads, or provider issues.
5. `TASKS.md` and all file exports are generated, read-only, non-authoritative, and never parsed for import.
6. Human notes created during an outage become attributable proposals only after recovery. They do not reserve work, change status, satisfy a gate, or establish ordering.
7. Valkey is derived, expendable coordination infrastructure. PostgreSQL retains task truth, leases, fencing, audit, and the transactional outbox.
8. The Mechanical Coordinator is non-LLM and deterministic. It may evaluate eligibility, dependencies, approval policy, leases, fencing, heartbeat, retry, expiry, and quarantine. It cannot invent scope, alter acceptance criteria, waive gates, certify, or merge.
9. **Certifier** is the final independent quality-gate role. Certifier may pass, reject, or escalate with evidence; it has no merge authority.
10. Every business and orchestration record is workspace-scoped; cross-workspace relationships are rejected.
11. Every mutation is idempotent and expected-version checked where it changes an aggregate.
12. Stale worker mutations are rejected by monotonically increasing fencing tokens.
13. Audit events are append-only and attributable; authoritative state is reconstructable from PostgreSQL without Valkey or files.

## 4. Configurable recovery posture only

Deployment tiers configure durability and operational recovery targets. They never configure SOT authority, fail-open writes, or gate bypass.

### 4.1 Tier defaults

| Setting                     |                                    Lite |                                                      Standard |                                                          High-assurance |
| --------------------------- | --------------------------------------: | ------------------------------------------------------------: | ----------------------------------------------------------------------: |
| Target RPO                  |                                24 hours |                                                        1 hour |                                                          **15 minutes** |
| Target RTO                  |                                24 hours |                                                       8 hours |                                                             **4 hours** |
| Base backup cadence         |                                   Daily |                                                         Daily |                                                               **Daily** |
| WAL archive cadence         |                                Disabled |                                              Every 15 minutes |                                                     **Every 5 minutes** |
| PITR retention              |                       0 days / disabled |                                                       14 days |                                                             **35 days** |
| Restore test frequency      |                               Quarterly |                                                     Quarterly |                                                             **Monthly** |
| Break-glass drill frequency |                                Annually |                                                  Semiannually |                                                           **Quarterly** |
| Off-cluster storage         | One encrypted off-cluster backup target | Encrypted off-cluster object storage, separate failure domain | **Encrypted off-cluster base backups and WAL, separate failure domain** |

A deployment MAY override defaults only through the validated recovery-posture contract. An override MUST record actor, reason, effective time, and policy revision. A claimed RPO MUST be no smaller than the actual backup/WAL mechanism can support. Enabling PITR requires WAL archival and off-cluster storage.

## 5. Functional requirements and acceptance criteria

### REQ-SOT-001 — Sole writable PostgreSQL authority

**Requirement:** All project, mission, milestone, task/tag/archive, dependency, assignment, execution/quarantine, lease, checkpoint, approval, outage proposal, event, link, artifact, and outbox mutations MUST commit through Gateway domain services into PostgreSQL.

**Acceptance:**

- Mutation journey tests show web, CLI, MCP, and agents invoke typed Gateway commands.
- Static/process inventory finds no file, Valkey, browser, or provider issue writer acting as canonical state.
- PostgreSQL state survives Valkey loss and reconstructs the same aggregate revisions.

### REQ-SOT-002 — Fail-closed mutation health

**Requirement:** A mutation MUST execute only while health state is `healthy`. `read-only-degraded` and `write-unavailable` MUST return the frozen deliberate-denial error contract and MUST NOT enqueue a hidden write.

**Acceptance:**

- Public health response is a discriminated union; contradictory state/proof combinations fail contract validation.
- Mutation methods accept only a fresh internal PostgreSQL transaction-local write proof, never caller-asserted/public health state.
- Negative tests reject expired proofs, policy-revision mismatch, Valkey-only liveness, and caller-forged `healthy`.
- Fault tests force both degraded states and prove row counts, outbox, files, and Valkey remain unchanged.
- Exact failure mapping proves authoritative 503 denial, retryable 502/504/timeout uncertainty, and 409 version conflict cannot cross-map.
- Replaying the same idempotency key after recovery returns one canonical result.

### REQ-SOT-003 — Generated projections

**Requirement:** `TASKS.md`, `mission.json`, and other exports MUST contain a non-authoritative header, workspace/project IDs, generated time, and source revision. No production parser may mutate DB from an export.

**Acceptance:**

- Generated output matches the API snapshot revision.
- Hand editing a projection fails CI validation or is overwritten by regeneration.
- Repository search finds no import path from generated projections.

### REQ-SOT-004 — Attributable outage proposals

**Requirement:** Human outage notes MAY be captured outside the system but, after recovery, can enter Mosaic only through workspace-scoped `change_proposals` attributed to an authenticated active member. A proposal stores source-note digest, target aggregate/version, typed command/payload, idempotency, lifecycle, decision actor/reason/time, and audit links. It MUST NOT silently change canonical state.

**Acceptance:**

- `(workspace_id, submitted_audit_event_id)` and `(workspace_id, accepted_command_audit_event_id)` are composite foreign keys to `task_events(workspace_id, id)`; missing and foreign-workspace event IDs fail before commit.
- Submission preallocates the proposal ID and atomically inserts `change_proposal.submitted` for that exact workspace/proposal with the new proposal referencing it.
- Accept locks proposal and target, obtains fresh write proof, checks expected version, executes the normal typed command, and atomically links that command's event for the same workspace/target and proposal causation.
- Negative tests reject missing submission events, foreign-workspace submission/acceptance events, and same-workspace events for an unrelated proposal, aggregate, target, or command.
- Tests prove a pending/rejected proposal cannot claim/order work, satisfy a dependency/gate, or mutate any target directly.

### REQ-TEN-001 — Workspace hard tenancy

**Requirement:** Every canonical business/orchestration row MUST carry `workspace_id`. Workspace-aware constraints and authorization MUST prevent cross-tenant relationships and reads/writes.

**Acceptance:**

- API, repository, import, WebSocket, and Coordinator negative tests reject foreign-workspace IDs without existence oracles.
- Project/task owners use exactly-one user/team references; assignment principals use exactly-one user/team/agent reference; agent/session targets are workspace-consistent.
- User owners, principals, proposers, and decision actors require ACTIVE workspace membership in the authoritative transaction.
- Dependency, project hierarchy, assignment, lease, checkpoint, approval-evidence, link, artifact, proposal target, and both proposal-audit-event composite relationships reject mixed workspaces.
- Tenant context is derived from authenticated authority, never accepted blindly from request data.

### REQ-ID-001 — Workspace identity and service scope

**Requirement:** Users, teams, agents, and agent sessions MUST be bound to a workspace with explicit role/capability scope. Agents MUST NOT receive raw DB credentials.

**Acceptance:**

- Workspace membership and service-identity tests enforce command-family scope.
- Revoked/disabled agents and ended sessions cannot claim, heartbeat, or submit.

### REQ-PLAN-001 — Normalized planning hierarchy

**Requirement:** Canonical planning entities are projects, milestones, missions, mission-milestone associations, and tasks. A task belongs to one required project and at most one mission/milestone/parent task.

**Acceptance:**

- CRUD tests preserve workspace, hierarchy, versions, and lifecycle constraints.
- Mission membership does not duplicate task status.
- Composite project-congruent constraints reject task→mission, task→milestone, task→parent, mission→milestone, and project→current-milestone mismatches.
- Parent and association constraints reject cycles/orphans where applicable.

### REQ-TASK-001 — Canonical task fields

**Requirement:** Tasks MUST support title, description, structured acceptance criteria, canonical status, priority, fractional board rank, accountable owner, assigned specialist role, due/not-before dates, estimate, progress, explicit blocker, retry policy, normalized workspace tags, non-lifecycle archival (`archived_at/by/reason`), metadata, monotonic fencing counter, and optimistic version.

**Acceptance:**

- API and UI round-trip every field without silent loss.
- Current `tasks.tags`, `assignee`, and `due_date` remain declared/preserved during N-1 and backfill to the canonical model without loss.
- Archive hides work without changing its canonical lifecycle status and requires actor/reason/time.
- Invalid status, rank, progress, date, owner, tag, archive, or retry data is rejected.
- Concurrent expected-version updates produce a visible conflict.

### REQ-TASK-002 — Fixed lifecycle and computed readiness

**Requirement:** Human workflow status MUST use the seven ratified values. Dependency/schedule/policy/lease/retry conditions MUST be exposed as computed readiness, not hidden status rewrites.

**Acceptance:**

- A dependency becoming incomplete changes readiness but does not silently rewrite the Kanban column.
- Readiness explanation identifies all active gates.
- State-machine tests reject illegal transitions and require reasons for blocked/cancelled paths.

### REQ-DEP-001 — Dependency DAG

**Requirement:** Workspace-local directed dependencies MUST be unique and acyclic. A task is dependency-eligible only after every blocking predecessor is `done` and completion conditions pass.

**Acceptance:**

- `(workspace_id, predecessor_task_id, successor_task_id)` is unique independent of dependency type.
- Cycle, duplicate, self-edge, and cross-workspace attempts fail before commit.
- Property/concurrency tests prove all blocking predecessors are evaluated.
- UI displays dependency and readiness errors accessibly.

### REQ-ASN-001 — Assignment is not a lease

**Requirement:** Assignment history and execution leases MUST be separate records. One persisted assignment identity freezes task version, exact target agent/session (or exactly-one non-agent principal), specialist role, expiry, state, policy revision, proposer, reason, and timestamps. Approval decisions relate to that assignment with workspace-aware constraints.

**Acceptance:**

- One assignment-state vocabulary is identical across schema, DTO, and engine.
- Lease acquisition accepts IDs only, then reloads and locks assignment, approval, task, and target session to verify workspace, current task version, exact target, state, expiry, and policy revision.
- Reassignment preserves history; assignment may exist without a lease; lease expiry does not erase ownership/evidence.

### REQ-AUD-001 — Semantic audit and outbox

**Requirement:** Mutating commands MUST append semantic `task_events` with actor, correlation, causation, idempotency key, and aggregate versions in the same transaction as state. Notifications MUST flow from a transactional outbox.

**Acceptance:**

- Atomicity tests prove state/event/outbox commit or roll back together.
- Proposal submission and acceptance tests prove their workspace-bound event links identify the exact submission and executed normal command, not merely an existing event UUID.
- Duplicate idempotency keys return the prior result without duplicate events.
- `task_events`, checkpoints, immutable artifacts, and evidence joins are INSERT/SELECT-only for application roles; parent hard deletes are RESTRICTed.
- Normal lifecycle uses archive/cancel, never hard delete; retention purge requires audited break-glass authority and evidence.
- Valkey outage leaves outbox pending and later replayable.

### REQ-API-001 — Typed Gateway command boundary

**Requirement:** Gateway MUST expose workspace-safe project/task/dependency/assignment/link/artifact/change-proposal queries and explicit lifecycle commands. Generic patching MUST NOT bypass claim, heartbeat, review, certify, proposal acceptance, or completion invariants.

**Acceptance:**

- KBN-105 freezes exact route, request, success, denial, conflict, and transport-normalization DTOs before CLI/web implementation.
- DTO validation, authorization, contract, and integration tests cover each command.
- Exact MCP-owned Gateway files are coder3-owned; coder4 consumes only frozen Gateway contracts.
- Endpoint registry aligns web, CLI, MCP, and generated client paths.
- Direct SQL and raw Valkey writes are absent from clients.

### REQ-UI-001 — Writable thin Kanban/List MVP

**Requirement:** Existing Tasks and Projects surfaces MUST become a real-data writable MVP with one shared query contract.

**Acceptance:**

- Users can create/edit/cancel/archive tasks, open task detail, and move cards within/across columns.
- Server validates transition and persists fractional board rank.
- Refresh, reconnect, CLI, MCP, and generated projection show the same revision.

### REQ-UI-002 — Tenant and work context

**Requirement:** UI MUST show workspace context and support filters for project, mission, milestone, status, priority, owner/specialist, due state, and tags.

**Acceptance:**

- Context is visible on every mutation surface.
- Filter tests cannot expose foreign-workspace data.
- Empty/loading/error states are explicit.

### REQ-UI-003 — Dependency, ownership, lease, and audit visibility

**Requirement:** Task detail MUST separate accountable owner, specialist assignment, active session/lease expiry, dependencies/readiness, acceptance criteria, blocker, external links, and audit timeline.

**Acceptance:**

- Each concept renders from its canonical endpoint.
- A lease is never displayed as ownership or completion.
- Conflict and stale-reconnect states require refresh rather than silent overwrite.

### REQ-UI-004 — Accessible interaction

**Requirement:** Kanban MUST support keyboard-accessible moves, non-drag alternatives, responsive layout, and semantic status/error announcements.

**Acceptance:**

- Keyboard journey performs every card transition available by drag.
- Automated accessibility checks and manual responsive checks pass.

### REQ-COORD-001 — Non-LLM Mechanical Coordinator

**Requirement:** Coordinator decisions MUST be deterministic from structured data and versioned policy. It MUST NOT invoke an LLM to interpret scope or acceptance criteria.

**Acceptance:**

- Pure decision engine receives complete immutable snapshots and performs no ID loading, SQL, Gateway, Valkey, or recovery I/O.
- Persistence/service adapter owns ID loading, transaction-local write proof, locking, persistence, and `recoverFromPostgres`.
- Same snapshot and policy revision produce the same eligibility/order explanation.
- Dependency, schedule, durable retry/quarantine, approval, role, and capacity inputs are auditable.
- Code/config inspection finds no model/provider dependency in the scheduling engine.

### REQ-COORD-002 — Eligibility and approval routing

**Requirement:** Only `ready` tasks under active project/mission, passed dependencies/schedule/retry/release policy, and without active lease may be proposed. Manual approval is default; auto-route requires an explicit approved policy revision.

**Acceptance:**

- Unapproved or gated tasks are never leased.
- Every persisted assignment proposal includes task version, exact target agent/session, expiry, state, deterministic reasons, and policy revision.
- Approval is relationally bound to the assignment identity and cannot be supplied as a forgeable proof-by-value DTO.
- Override/reject/reassign requires an attributable reason.

### REQ-COORD-003 — Atomic lease, heartbeat, fencing, and recovery

**Requirement:** Lease acquisition MUST be atomic in PostgreSQL, permit at most one active lease per task, atomically increment the durable per-task fencing counter under task lock, use bigint-safe tokens, require timely acknowledgement/heartbeat, and reject stale workers. Lease and checkpoint relations MUST bind the exact workspace+task+assignment/session+fence.

**Acceptance:**

- Concurrent claim tests yield one winner and strictly increasing fencing tokens.
- Lower/expired tokens and mismatched same-workspace task/assignment/lease/checkpoint IDs fail.
- Token values round-trip as bigint/decimal strings without JavaScript precision loss.
- Coordinator restart reconstructs lease/retry/quarantine state from PostgreSQL alone.

### REQ-COORD-004 — Retry and quarantine

**Requirement:** Missing acknowledgement, agent loss, or execution failure MUST produce a deterministic release, bounded backoff retry, or quarantine outcome according to retry policy. Ambiguous/non-idempotent work requires Sub-Orchestrator action.

**Acceptance:**

- Durable execution state records disposition, attempt/max, next eligibility, terminal reason, actor/policy, timestamps, and version.
- Retry budget/backoff are bounded and tested.
- Exhausted or non-idempotent failures quarantine with workspace-scoped artifact evidence.
- One specialist-role vocabulary is enforced across schema, sessions, assignments, DTOs, and engine.
- No task loops indefinitely or silently returns to ready.

### REQ-GATE-001 — Role and authority chain

**Requirement:** Canonical flow is User → Interaction → Portfolio Orchestrator → Project Sub-Orchestrator → Gateway → domain services → Mechanical Coordinator → specialists → Certifier.

**Acceptance:**

- Role bindings and approvals are queryable and audited.
- Coordinator cannot create scope or waive gates.
- Certifier cannot merge or close provider artifacts.

### REQ-GATE-002 — Independent review and certification

**Requirement:** Author and reviewer MUST differ. Auth, security, tenant, secrets, and data-integrity surfaces MUST receive mandatory SecReview. Certifier is the final quality gate after remediation.

**Acceptance:**

- Gate tests reject author self-review and missing required SecReview.
- Certifier receives complete traceability/evidence and returns pass/reject/escalate.
- A Certifier pass does not grant merge authority.

### REQ-REC-001 — Recovery posture validation

**Requirement:** A deployment MUST select a validated Lite, Standard, or High-assurance posture and MAY override only recovery knobs.

**Acceptance:**

- Runtime invokes normative `validateRecoveryPostureV1`, not shape-only JSON Schema validation.
- Validator rejects PITR/WAL mismatch, impossible RPO, unknown fields, non-encrypted/non-separated storage, and weakened High-assurance values.
- A bounded recovery/infra slice owns parser wiring, override audit, mechanism verification, restore test, and break-glass evidence.
- High-assurance defaults equal RPO 15m/RTO 4h, encrypted off-cluster WAL every 5m, 35d PITR, daily base backup, monthly restore test, and quarterly break-glass.

### REQ-MIG-001 — One-way shadow migration

**Requirement:** Migration from jarvis-brain/Vikunja MUST use inventory, immutable source snapshots/checksums, one-way shadow import, read reconciliation, write freeze, final delta, cutover, and read-only stabilization. Dual writes are forbidden.

**Acceptance:**

- P0 publishes the current `origin/main` field-by-field expand/backfill/compatibility/switch/contract map before any schema lane starts.
- Legacy columns remain in the unified Drizzle declaration for the entire expand/N-1 window.
- Dry-run/apply/verify modes are idempotent and workspace-safe.
- Import lineage preserves source system/key/file/checksum/batch and rejected-record reports.
- Empty DB, production-shape, partial-resume, downgrade/rollback, status-shadow, workspace-backfill, and `mission_tasks.status` retirement tests pass.
- Shadow records cannot auto-dispatch.

### REQ-MIG-002 — Cutover and rollback safety

**Requirement:** Cutover MUST disable legacy writers and switch all clients to Gateway. Before first DB mutation rollback may switch authority back; afterward rollback requires freeze, DB-delta export/reconciliation, and owner decision.

**Acceptance:**

- Process inventory proves no active jarvis-brain/Vikunja project/task writer.
- Cutover rehearsal meets signed reconciliation thresholds.
- No reverse and forward sync run concurrently.

## 6. Explicit non-goals

The P0–P3 canon does not authorize:

- replacing Gitea issue/PR storage;
- calendar, email, GLPI cache, CRM, billing, time tracking, or personal-brain migration;
- arbitrary custom workflows/statuses/fields;
- a writable offline/file/Valkey/browser fallback;
- direct client database access;
- LLM scheduling or autonomous scope invention;
- Coordinator gate waiver, certification, merge, release, or provider issue closure;
- Certifier merge authority;
- full mission designer, portfolio analytics, critical-path UX, or advanced board customization in the thin MVP;
- P4/P5 features unless separately released.

## 7. Global release evidence

P0–P3 may close only when requirements traceability maps every requirement above to automated and situational evidence, including cross-workspace denials, DB/Valkey fault injection, concurrent leases, stale fencing, generated-file immutability, UI conflict/reconnect behavior, migration reconciliation, independent review, mandatory SecReview, and final Certifier evidence.

## 8. Amendment A1 — hierarchy parentage and RBAC chain above workspaces

**Status:** amendment to the ratified canon, added by reviewed PR under
decision D13 (operator ruling, 2026-08-25; decision owner Jason). It adds
parent structure ABOVE workspaces. Sections 1–7, every invariant in §3, and
every REQ above remain binding verbatim, with exactly one express modification:
the narrow portfolio-analytics carve-out stated in §8.2.4. Nothing else below
this line is weakened.

### 8.1 What is added

1. A platform hierarchy exists above workspaces:
   **company/organization → estate → platform-project → workspace**. Each
   workspace belongs to exactly one platform-project, each platform-project to
   exactly one estate, each estate to exactly one company.
2. **Record class.** Hierarchy records (company, estate, platform-project,
   their parentage edges, and hierarchy-level access grants) are a new,
   explicitly named record class: **tenancy/authorization structure records**.
   They are not business or orchestration records, so §3 invariant 10 and
   REQ-TEN-001 do not apply to them and are not weakened by them — those two
   requirements bind business/orchestration rows exactly as before.
   Constraints on the new class:
   - Hierarchy tables MUST NOT carry task, plan, or any other
     business/orchestration payload — parentage, naming, and grant data only.
   - A hierarchy record can never be the subject of work: it cannot be
     claimed, ordered, gated, or referenced as a dependency by any
     business/orchestration row.
   - Hierarchy mutations flow through the same sole-writable-SOT, fail-closed,
     audited mutation path as everything else (§8.2.3).
3. The hierarchy serves exactly two runtime functions, plus audited
   maintenance of its own structure:
   - **RBAC evaluation:** access grants are declared per company, estate, or
     platform-project and evaluate down the chain to workspace-scoped
     authorization. Tenant context continues to be derived from authenticated
     authority (REQ-TEN-001); the chain adds where grants can be declared,
     not a bypass of workspace authorization.
   - **Read-only roll-ups:** task and status visualization bubbles up the
     hierarchy as aggregation over workspaces the reader is authorized on.
   - **Chain maintenance (not a third runtime function):** re-parenting an
     asset — moving a workspace to another platform-project, a
     platform-project to another estate, and so on ("assets are transferable
     subject to the structure", PRD Part I §4) — is an audited edit of the
     hierarchy records themselves under §8.3. It never modifies
     business/orchestration rows and never crosses a workspace boundary for
     them; the workspace's contents move with the workspace untouched.
4. Naming: this amendment says **platform-project** for the hierarchy level
   above workspaces, because §5 REQ-PLAN-001 already defines `projects` as
   planning entities INSIDE a workspace. The two are different objects. Final
   terminology (rename of one or the other) is an implementation-PR decision
   under this amendment's review; the schema MUST NOT merge them.

### 8.2 What is explicitly unchanged

1. `workspace_id` remains the hard mechanical isolation unit (§2 D2,
   REQ-TEN-001). Hierarchy tables carry parentage; they do not create
   cross-workspace relationships between business/orchestration rows, which
   remain rejected (§3 invariant 10).
2. Roll-up is **never a write**: no aggregation path may mutate, claim, order,
   or gate work in any workspace. Bubble-up views are generated projections in
   the sense of §3 invariant 5 — non-authoritative and never import sources.
3. Fail-closed mutation health (§3 invariants 3–4), sole writable PostgreSQL
   SOT, fencing, audit, and the Coordinator/Certifier authority rules are
   untouched.
4. No §6 non-goal is authorized, with one express, narrow carve-out that this
   amendment makes to the "portfolio analytics" non-goal: the read-only
   roll-up of §8.1 — per-workspace task counts and statuses aggregated up the
   parent chain, over workspaces the reader is authorized on — is in scope.
   Everything beyond that boundary (metrics, trends, forecasting, scoring,
   dashboards computed across workspaces, any derived analytic that is not a
   direct count/status aggregation) remains a non-goal. This is an explicit
   narrowing by amendment, not a claim that §6 is unchanged; every other §6
   non-goal is untouched.

### 8.3 Acceptance (binding on the implementing PRs)

- Schema tests prove each workspace resolves to exactly one
  platform-project/estate/company chain and that chain edits are audited.
- Authorization tests prove a grant at each hierarchy level yields exactly the
  workspace permissions the chain implies, and that revocation up the chain
  propagates.
- Negative tests prove roll-up endpoints cannot mutate state and that a
  reader sees aggregates only over workspaces they are authorized on
  (no cross-tenant existence oracles).

## 9. Amendment A2 — company visibility classes and the company directory

**Status:** amendment to Amendment A1, added by reviewed PR under Ruling 4b
(operator ruling, 2026-08-27; decision owner Jason; recorded in the webui-audit
lane RULINGS.md). Everything in §§1–8 remains binding verbatim, with exactly
the two express modifications below. Nothing else is weakened. The detailed
contract text lives in the hierarchy schema contract
(`hierarchy-schema.md` §2.8, §5.5, §6.9); this amendment changes only what A1
itself permits, so that contract does not stretch A1 by interpretation.

### 9.1 What A2 modifies in A1

1. **Class data (extends §8.1.2's first constraint).** The tenancy/authorization
   structure record class additionally carries **visibility-class data**: the
   single column `companies.visibility`, values `private` | `directory`
   (hierarchy schema §2.8). Visibility is disclosure data about the class's own
   nodes — what a company row reveals about its own existence — and is part of
   the class's tenancy/authorization purpose. It is not business or
   orchestration payload. §8.1.2's payload prohibition is widened for nothing
   else: hierarchy tables still MUST NOT carry task, plan, or any other
   business/orchestration payload, and this amendment admits exactly this one
   column.
2. **The company directory (extends §8.1.3's function enumeration).** The
   hierarchy serves one additional, express, narrow runtime function: the
   **company directory** — a read-only disclosure listing of exactly the
   companies whose `visibility = 'directory'`, revealing existence, name, and
   slug to every authenticated user of the deployment and nothing else. It
   mutates nothing, confers no authority, evaluates no grant down the chain,
   and aggregates nothing (it is not a roll-up). §8.3's
   no-cross-tenant-existence-oracle acceptance is narrowed by exactly this one
   ratified carve-out: the directory is the sole permitted existence
   disclosure, and it discloses only directory-class companies (witnessed in
   hierarchy schema §6.7 and §6.9). Private companies remain undisclosed to
   non-granted subjects everywhere, including the directory.

### 9.2 What A2 explicitly does not change

1. Content access stays grant-only under the RBAC grant model contract:
   directory listing discloses existence, never content, membership, or any
   authority (Ruling 3 unchanged; hierarchy schema §2.8).
2. **No join-request surface is authorized.** Ruling 4b decision 5's
   see-and-ask-to-join flow is a follow-up contract in its entirety —
   including the ability to submit a request. A2 admits exactly the
   read-only listing of §9.1.2 and nothing more; hierarchy schema §2.8
   states the invariants that pre-bind the future flow contract, and that
   contract must itself amend this enumeration before any join-request
   runtime surface exists.
3. Visibility changes are hierarchy mutations on the existing §8.2.3 audited
   mutation path — audited maintenance of the class's own structure in
   §8.1.3's sense, not a further runtime function. Authorization for them is
   defined in hierarchy schema §5.5 (platform admins plus the future
   company-CRUD capability; owner-as-such cannot publish).
4. Company creation is unchanged and always yields `visibility = 'private'`
   (onboarding wizard §5.2); this amendment adds no creation path and no
   default-open disclosure.
5. Every other constraint of A1 — §8.1.2's remaining bullets, §8.2 in full,
   and §8.3's other acceptance criteria — is untouched.
