Initiatives
Initiative Brief: Per-Initiative Repository Isolation and Applications
# Initiative Brief: Per-Initiative Repository Isolation and Applications ## Desired outcome An initiative has a **durable, authoritative repository scope** stored in PostgreSQL. That set — not the brief, not `repositoryHints`, not the repositories its work items happen to reference — is the answer to "what may this initiative touch?" Every service that creates or mutates repository-targeted state on behalf of an initiative consults it and fails explicitly when a target falls outside it. Scope never widens as a side effect of planning, brief commits, hints, or history. **Applications** are first-class persisted Orchestrator records: a named logical group of repositories drawn from the trusted registry, with membership managed through the UI. A repository may belong to many Applications. An operator picks an Application when setting up an initiative and uses it to **populate** the initiative's scope; from that moment the initiative's scope is its own set, freely edited, and later changes to the Application never mutate it. The association is kept as context, not as a rule. `primaryRepository` becomes a real, nullable, persisted, operator-selectable property of the initiative — not a derivation input every caller omits. Three concepts, with **one** trust boundary and two independent memberships beneath it: 1. **Trusted repository registry** (code, ADR-0006) — what Orchestrator may operate on at all. The only trust boundary. 2. **Application** (persisted, UI-managed) — a logical grouping drawn from the registry. An input to scope, not a parent boundary over it. 3. **Initiative repository scope** (persisted, per initiative) — what *this* initiative may touch, drawn from the registry. Application membership and initiative scope are each independently constrained by the registry, and **not by each other**. An initiative populated from the "Outshine" Application may then add `Xyence/hub` because this particular piece of work needs it; the result is a scope that is not a subset of any Application, and that is a correct and expected outcome. Cross-application work is the case this design exists to support. Everything an operator needs to run this is in the UI, and served over `/orchestrator/*` so the Workspaces operator app uses the same surface rather than reaching into Orchestrator-only state. ## Motivation Issue #146 asked for repository-*independent* initiatives. #147 delivered a pure classifier (`deriveInitiativeRepositoryScope`) and a read-only panel, and stopped there. The classification has no storage, no operator control, and no consequence, so "scope" today is a description of what already happened rather than a boundary. The gap is not theoretical. Repository scope is recomputed on every render from the brief's `repositoryScope`, `context.repositoryHints` (jsonb, overwritten wholesale on brief commit), and the distinct repositories of existing work items. Nothing consults it. The planner receives the entire trusted registry on every pass, with hints reduced to a prompt line it is explicitly permitted to drop. Plan materialization checks registry membership, frozen state and the item's own contract — never the initiative. So an initiative whose brief declares one repository can silently acquire work in five others, and the only signal is the same read-only panel, after the fact, labelled "discovered". Two of #146's own requirements were never met at all: the operator-designated primary repository is an input no caller supplies, and "remove repositories that are no longer required" has no implementation anywhere. Worse, one canonical route accepts a repository with no validation of any kind. `fileWorkItem` (`packages/db/src/services/filedWorkItems.ts:43`) runs no registry check, no frozen check and no scope check; it persists the work item and sets `contract.allowedRepositories` to whatever string it was handed. `POST /orchestrator/initiatives/[id]/work-items/file` (#608, shipped 2026-08-24) exposes that to any authenticated operator or automation. Materialization later refuses with "untrusted repository" non-fatally, so the row persists in `PLANNED` and the wave — whose continuation means every item complete — cannot close. This is precisely why UI filtering cannot be the boundary. It is tracked independently as Xyence/orchestrator#610, because the registry, frozen and contract-consistency checks it is missing are owed whether or not scope enforcement is ever built. Separately, the system needs repository groups and has grown four incompatible partial answers — a Hub-manifest Application whose ingest has never worked, a per-repository `application` label that cannot express a group, the Application Platform's single-repository Applications with no table behind them, and release bundles, which work but are release-only. An operator scoping an initiative to "the platform" has no way to say so. ## Current state - What #146/#147 left standing - `packages/domain/src/initiativeScope.ts` — `deriveInitiativeRepositoryScope` and `expectedRepositoriesFromBriefScope`. Pure, well tested, recomputed per render. - Two consumers only: `apps/web/src/components/initiativeScopeView.ts`, and `packages/db/src/services/briefIntake.ts:300`, which seeds `context.repositoryHints` at import. - `apps/web/src/app/initiatives/[id]/page.tsx:431` calls the view with `briefSourceRepository`, `expectedRepositories` (brief `repositoryScope` + `context.repositoryHints`) and `activeRepositories` (distinct work-item repositories). It passes neither `primaryRepository` nor `discoveredRepositories`, so the primary is always the first expected repository and "discovered" means only "carries work but was not expected". - No durable scope object exists. `initiatives.context` (jsonb) holds `repositoryHints`, writable at creation, via `PATCH /api/initiatives/[id]`, and overwritten wholesale on brief commit (`apps/web/src/app/api/initiatives/[id]/brief/commit/route.ts:39`). - `packages/db/src/services/epics.ts:98` creates initiatives with `repositoryHints: [epic.repository]` — a second seeding path. Where repository targets are validated today, and against what — Every site below enforces the same two rules — trusted registry and not frozen — and none of them knows what initiative it is serving. | Seam | Location | Checks today | | --- | --- | --- | | Plan persistence | `packages/db/src/services/plans.ts:311-343` | contract `allowedRepositories`, `isKnownRepository`, `isFrozenRepository`, trusted validation keys | | Work-item amendment | `packages/db/src/services/workItems.ts:189-206` | same four | | Filed work item | `packages/db/src/services/filedWorkItems.ts:43` | **none** — tracked as #610 | | Issue import | `packages/db/src/services/importedIssues.ts:154-175` | registry, frozen, issue eligibility | | Epic link | `packages/db/src/services/epics.ts:58-63` | registry, frozen | | Related-epic declaration | `packages/db/src/services/relatedEpics.ts:65` | registry | | GitHub issue materialization | `packages/github/src/sync.ts:169` | registry (per item, non-fatal) | | PR creation | `packages/github/src/sync.ts:278` | repository read from the work item; run/lease ownership | | Worker claim | `packages/db/src/services/runs.ts:235-240` | worker credential capabilities only | The planner's world - `repositoryCatalog()` (`apps/web/src/server/planner.ts:74-86`) maps all of `REPOSITORIES`, unfiltered, and is used for first-wave (`:439`) and continuation (`:824`) planning alike. - The prompt says: *"Target ONLY repositories from the provided catalog. You may add or drop the operator's repository hints, but explain why in assumptions."* - `continuationRepositoryHints()` (`:805`) unions expected with already-modified repositories — widening the hint, constraining nothing. - `roadmapCandidatesFor()` (`:131`) selects roadmap candidates from `repositoryHints`. - Planner assumptions and normalizations already have a persistence path (`recordPlannerNormalizations`, `:455`). The UI - Every repository control on the standalone initiative page binds to `KNOWN_REPOSITORY_NAMES`: plan editor (`:673`), issue assembly (`:238`, `:701`), importer (`:641`, frozen filtered). - The Workspaces operator app (`Xyence/workspaces`, `apps/orchestrator`) has **no** repository surface at all — not on initiative detail, the list, or `/initiatives/new` — because `apps/web/src/server/canonicalInitiatives.ts` exposes no repository data. - `/api/repositories` lists the trusted registry but is gated behind an ENGINEERING RBAC middleware rule and the `REPOSITORIES_SURFACE_ENABLED` flag, which is off by default. It cannot serve a repository picker in Workspaces. The four meanings of "Application" - **`TopologyApplication`** (`packages/domain/src/topology.ts`) — id, name, owningTeam, components, `repositories[]`. Already a repository group, read from a Hub manifest at request time, persisted nowhere, consumed by `/applications` and `/applications/repositories` and nothing else. - **`PLATFORM_APPLICATION_MAPPING_SEED`** (`packages/policy/src/platformMapping.ts`) — a per-repository `application` label, strictly 1:1, seeded in code, overridable by `REPOSITORY_PLATFORM_MAPPING_JSON`. - **Application Platform Applications** (#501/#502/#508/#585) — one repository each. The Hub-manifest guide states Orchestrator owns Application identity and lifecycle, but there is no `applications` table in `packages/db/src/schema.ts`, and platform status resolves through a single hardcoded slug (`applicationStatus.ts`). - **`RELEASE_BUNDLES`** (`packages/policy/src/bundles.ts`) — the only functioning group: named, deploy-ordered, validated at startup in both directions. Release-only, a code constant, and it forbids a repository from belonging to two bundles because deploy order must be unambiguous. The Hub topology manifest ingest has never worked - `topologyManifest.ts:57` looks for `platform-topology.json`; Hub publishes `platform-topology/topology.yaml`. - `topologyManifest.ts:260` calls `JSON.parse`. The manifest is YAML; there is no YAML parser on that path. - The schema requires `version: number`, `owningTeam` per application and `repositories: ["org/name"]`. Hub writes `schema_version: "1.0"`, carries no per-application team, and uses `primary_repos: [outshine, hub]` — short keys. - Consequently `/applications` resolves to `unavailable` against the real manifest and has never displayed it. Overlapping membership is already the reality — Hub's manifest states the principle in its own header: *"A repository may contribute components to more than one application (e.g. hub → Platform and Orchestrator), which is exactly why applications — not repositories — are the top-level abstraction."* Its current data agrees: `outshine` is in `platform`, `content-management` and `console`; `hub` is in `platform` and `orchestrator`; `workspaces` is in `workspaces` and `orchestrator`; `stlouis-xyence-io` is in `content-management` and `st-louis-site`. Its Applications include cross-cutting capabilities such as `content-management` (`status: in-development`, spanning three repositories) — exactly the shape an initiative wants to scope to. ## Product principles - Scope is a decision, not a description. The operator states it; the system never infers it from what has already been touched. - An Application is a starting point, not a leash. It populates a scope and is then remembered as context; it never changes a scope on its own. - A refusal explains itself in operator language. "Xyence/console is not in this initiative's scope" with the current scope and the action that would change it — never a database constraint error. - Removing a repository is answered at the level of the work, not the row. If planned or active work targets it, the operator is shown that work and asked to resolve it. - One action for the common case: scoping to a known product is picking an Application. - Nothing in flight breaks. Every existing initiative is given a scope matching what it is already permitted to do, before anything is enforced. - Every operator capability here exists in the UI. A capability reachable only by API is not delivered. - The operator does this in the Workspaces app; standalone pages keep pace as break-glass. ## Architectural principles - Repository scope, Applications and Application membership are durable PostgreSQL state. Nothing about the boundary is reconstructed at read time. - There is exactly one trust boundary — the trusted registry — and two independent memberships beneath it: registry ⊇ Application membership, and, separately, registry ⊇ initiative scope. Applications populate scope by value; they never bound it afterward. No validation anywhere may require an initiative's scope to be a subset of its associated Application's membership. - Admission is checked at admission time, and admission is the only moment the registry gates. A repository that is frozen or leaves the registry after admission is retained, marked, and blocked — never silently deleted from an Application or an initiative. Boundaries move because an actor moved them. - The trusted registry stays code-owned under ADR-0006. Applications are operator data: every mutation carries a human actor, is validated against the registry, and is audited. "Trusted operator configuration, never model output" is satisfied by actor and validation, not by the file the data lives in — no planner, agent or model output may create or alter an Application. - Enforcement lives in the domain/service layer, not in routes and not in the UI. One shared guard is called by every seam that accepts an initiative identity and a repository target. - The planner is given a scoped world *and* its output is re-validated on persistence. Narrowing the catalog is an efficiency and honesty measure; the persistence check is the guarantee. - The existing pure derivation stays pure and becomes a **display classifier over persisted entries** — origin drives status, replacing set arithmetic over hints and work items. - Orchestrator owns the operational Application record. The Hub manifest is an import/export peer, reconciled explicitly on demand, never read on the request path for a runtime decision. - Scope mutations are recorded on the initiative's existing append-only timeline (`run_events`) with an actor; Application mutations are recorded in `audit_log`. - The canonical surface distinguishes an unset scope from an empty one, and additive fields only — no existing canonical field changes meaning. ## Domain concepts - Trusted repository registry: `REPOSITORIES` in `@orchestrator/policy`. The set Orchestrator may operate on at all. Code-owned, ADR-0006. Unchanged by this initiative. - Application: a persisted, named logical group of trusted repositories, managed through the UI. A repository may belong to zero, one, or many. An Application is a template an operator populates a scope from; it does not bound that scope afterward. - Application membership: the persisted set of repositories in an Application. Validated against the registry on every write and at startup. - Initiative repository scope: the persisted, authoritative set of repositories one initiative may operate on. Its own set, not a view of anything else. - Scope state: whether an initiative's scope has been established (`set`) or never was (`unset`). An unset scope is not an empty scope unset blocks planning with an explanation; empty is a deliberate operator statement. - Admission: the recorded act of adding a repository to an initiative's scope actor, time, origin, and the Application it came from when it came from one. - Origin: why a repository is in scope `brief`, `operator`, `application`, `planner_suggestion`, or `migration`. Origin is provenance for display and review; it grants nothing. - Blocked entry: a repository still in an Application or an initiative's scope that has since been frozen or removed from the trusted registry. It stays visible and marked, its historical work stays intact, no new repository-targeted operation may use it, and only an operator can remove it. - Primary repository: the operator-designated principal repository of an initiative. Nullable and never invented; when set, always a member of scope. - Associated Application: the Application an initiative's scope was populated from, retained as context. It has no ongoing effect on scope. - Scope suggestion: a trusted repository proposed for scope but not admitted named by the planner in its assumptions, carried in `context.repositoryHints`, or declared by a brief commit. Rendered with Add and Dismiss. Not a work item, not a question, and never an automatic admission. - Trusted repository registry entry: repository policy description, default branch, validation commands, protected paths, frozen flag. Supplies the metadata the planner and UI show for in-scope repositories. - Release bundle: the existing release-time group with deploy ordering. Unrelated to Applications and unchanged. ## Decisions - Applications are first-class persisted Orchestrator data — Membership is database state managed through the UI, not code or environment configuration. Seeding from trusted config or topology data is initialization only; the persisted record is the operational source of truth thereafter. - The trusted registry remains the only trust boundary — Application membership and initiative scope are each validated against it on admission, independently of one another. Membership can never launder an untrusted or frozen repository into an initiative. - An initiative's scope is not required to be a subset of its associated Application — An operator may add any trusted repository the work needs. Encoding the subset relation as a validation rule would forbid exactly the cross-application work this design exists to support, so no such rule may be written. - A repository frozen or removed from the registry after admission stays visible and blocked — It is not deleted from any Application or initiative scope. It is marked, its existing work stays intact and legible, every new repository-targeted operation against it is refused, and only an explicit operator action removes it once the affected work is resolved. Scope boundaries move because an actor moves them, never because upstream configuration changed. - A repository may belong to many Applications — Hub's manifest asserts this as the reason Applications are the top-level abstraction, and its current data already does it in four places. `RELEASE_BUNDLES`' single-membership rule exists because deploy order must be unambiguous; that reason does not transfer to scoping, so the constraint is not inherited. - Initiative repository scope is persisted on the initiative — A dedicated membership table, authoritative after migration. Derivation from hints, brief sections and work items is retired as a source of truth and retained only as a display classifier and as migration input. - Applications populate scope; they do not define it — Selecting an Application copies its repositories into the initiative's scope as ordinary entries. The association is stored as context. A later membership change never mutates an existing initiative's scope. - `primaryRepository` is a persisted, nullable initiative column — Operator-selectable, exposed canonically, required to be in scope when set, and never invented when the initiative does not need one. - Enforcement is a single shared domain guard called at every seam — Not a route check, not a UI filter, and not the planner prompt. Every service accepting an initiative identity and a repository target calls it. - The planner receives only in-scope repositories, and its output is re-validated on persistence — Prompt scoping alone is not enforcement; malformed or generated output naming an out-of-scope repository is rejected at write time. - Out-of-scope planner proposals become scope suggestions, not new objects — The planner already records assumptions and normalizations; a named-but-unavailable repository surfaces there and in the UI as a one-click addition. No new table, and no auto-routing through the question resolver, which would put a trust decision on a model-facing path. - Repository hints are retained as descriptive planner context and grant nothing — Their meaning narrows; they are not deprecated or removed. - Scope changes are recorded on the initiative timeline — A new `scope_changed` run-event kind, with the actor and the repositories added or removed. Application mutations go to `audit_log`. - Removing a repository with planned or active work is refused at the operator level — The UI names the blocking work items and requires the operator to resolve them. Historical or terminal references never block removal, and never re-add a removed repository. - Orchestrator's Application record is operational; Hub's manifest is a peer to import from and export to — Synchronization is explicit and on demand. No runtime decision reads the manifest. - One Application association per initiative for V1 — Stored as context, nullable. Widening to several later breaks nothing, because scope is populated by value and never bounded by an Application. Settled as a V1 constraint; it does not change what must be built now. - The persisted model and enforcement land before any UI filtering is treated as sufficient — Sequencing is part of the design, not a delivery preference. - The filed-work-item defect is referenced, not absorbed — Xyence/orchestrator#610 is a pre-existing invariant violation with its own acceptance criteria. This initiative requires it satisfied during the enforcement phase; it does not restate or own it. ## Rejected / deferred alternatives - Code- or environment-configured Application membership — Rejected by decision membership is operator data and belongs in the database with UI management. The registry, not the storage medium, is the trust boundary. - Live-linking Applications to initiative scope — Editing a group would silently change the boundary of every initiative that used it. Scope is populated by value; re-sync is an explicit, recorded action. - Inheriting the single-membership constraint from release bundles — Its justification is deploy-order determinism, which scoping does not have. Hub's data already overlaps. - Inventing a new grouping abstraction — One logical concept, reusing the topology Application's semantics. - Coupling initiative isolation to live Hub-manifest reads — Orchestrator needs its own durable representation for an operational decision on the hot path. - Planner prompt scoping as the enforcement mechanism — Prompt instructions are not a boundary; persistence checks are. - Enforcing scope only in the worker — The worker cannot be the boundary for work that should never have been planned. Its check is defence in depth. - A separate discovery-request object — Planner assumptions already persist; adding a table would duplicate a mechanism that exists. - Reusing the `questions` queue for out-of-scope proposals — Questions are routed to a clarification resolver, which would place a trust decision on a model-facing path. - Blocking repository discovery entirely — #146's central case is a repository that turns out to be needed. It becomes a suggestion the operator admits, not a refusal. - Tombstoning removed scope entries — Keeping removed rows reintroduces the inference problem. Removal is a delete; the history lives on the append-only timeline. - [deferred] Folding release bundles into Applications — Bundles carry deploy dependencies and a validated exclusivity rule. They will overlap Applications and are untouched here. - [deferred] Replacing the per-repository `application` label — A repository now has several Applications, so the singular label cannot be derived from membership. It stays as a display field on the repository surfaces and is reconciled separately. - [deferred] Making `/orchestrator/content/applications` a projection of the Application catalog — The content-Application discovery surface stays as it is; unifying it is a follow-on, not a blocker. - [deferred] Converging the Application Platform's created-Application lifecycle with this catalog — The coherent end state, and the reason this brief keeps one concept, but it touches the create-Application flow, Hub manifest generation and platform status. Later architectural work; it changes nothing about what is built here. - [deferred] Repairing the Hub manifest ingest as a prerequisite — It is broken four ways and is not on the critical path. Seeding transcribes the manifest's Applications once; repair and two-way sync are sequenced after enforcement lands. ## Constraints - Two repositories change: `Xyence/orchestrator` (schema, domain, policy, services, planner, canonical API, standalone pages) and `Xyence/workspaces` (`apps/orchestrator` — the operator UI and its API client). - Schema changes are made in `packages/db/src/schema.ts` followed by `pnpm db:generate`; files under `packages/db/drizzle/` are never hand-edited. This initiative adds tables, columns, and two enum values. - `@orchestrator/domain` stays SDK-free and pure; the scope classifier and the admission/removal rules are pure functions with unit tests. - All model/provider output crossing an adapter boundary stays zod-validated and fails closed. - No workflow state outside PostgreSQL; every mutation records an actor string (`human:*`, `worker:*`, `agent:*`, `system`). - Application and scope mutations may never be authored by a model. The services accept only human or system actors for these operations. - `.github/workflows/**` is a protected path in both repositories. - No new credentials, tokens or auth schemes — the Workspaces app reuses its existing scoped client and platform session. - Existing initiatives, plans and in-flight waves keep working through the migration; no currently valid operation becomes invalid at cutover. - Canonical API changes are additive; no existing field changes meaning or disappears. - The topology manifest's failure modes stay non-fatal: a missing or malformed manifest degrades to guidance, never a crash. Delivery sequencing - Schema, domain model and services first: `applications`, `application_repositories`, `initiative_repositories`, `initiatives.primary_repository`, `initiatives.application_id`, `initiatives.repository_scope_state`, the `scope_changed` event kind, and the shared `assertRepositoryInScope` guard. - Migration and backfill second, with a dry-run report an operator can read before it is applied. - Enforcement third, at every seam in the inventory, beginning with the filed-work-item path — #610 — because it validates nothing today. That issue may land independently first; if it has not, this phase closes it. - Planner scoping fourth: scoped catalog, scope-derived continuation and roadmap selection, contract subset validation, scope suggestions from assumptions. - Canonical API fifth. - UI last, in both apps. No UI filtering is treated as satisfying an acceptance criterion until the corresponding service-layer check exists. ## Invariants - Every repository admitted to an Application is in the trusted registry at the moment of admission. - Every repository admitted to an initiative's scope is in the trusted registry at the moment of admission. - A repository may belong to zero, one, or many Applications. - An initiative's scope is not required to be a subset of its associated Application's membership, and no validation may enforce that relation. - `primaryRepository`, when non-null, is a member of the initiative's scope. - The repository context given to the planner is a subset of the initiative's scope. - No persisted plan or work item may newly target a repository outside its initiative's scope, regardless of what the planner returned. - No initiative-scoped execution or GitHub action may target a repository outside the initiative's scope. - Application membership changes never mutate an existing initiative's scope. - Repository hints grant no repository access; they are descriptive context only. - Historical work-item references never re-add a repository an operator removed from scope. - An initiative with `repository_scope_state = 'unset'` cannot be planned, and the refusal says so. - A frozen repository can never be admitted to an Application or an initiative's scope. - A repository frozen or removed from the trusted registry after admission remains in every Application and every initiative scope that holds it, marked as blocked; it is never removed automatically, its existing work stays intact, and no new planning, filing, execution or GitHub action may target it. - A blocked repository is excluded from scope population when an Application is used to populate an initiative, and never appears in the planner's catalog. - Removing a repository is refused while any work item targeting it is in a non-terminal state. - Every scope change and every Application mutation has a recorded human or system actor; no model-authored actor may perform either. - The brief source repository is never admitted as an implementation target. ## Repository scope - `Xyence/orchestrator` — schema and migrations, domain scope and Application models, policy admissibility helpers, services and the shared enforcement guard, planner scoping, canonical `/orchestrator/*` routes, standalone `apps/web` pages. - `Xyence/workspaces` — `apps/orchestrator`: initiative scope panel, new-initiative scope step, Applications management surface, scope-bound repository pickers, API client. ## Expected behavior - Data model - `applications` — `id`, `key` (stable slug, unique), `name`, `description`, `owningTeam` (nullable), `status` (`active` | `archived`), `source` (`seed` | `operator` | `topology_import`), `topologyId` (nullable link to a Hub manifest application id), `createdByActor`, timestamps. - `application_repositories` — `id`, `applicationId` (cascade delete), `repository`, `addedByActor`, `addedAt`; unique on `(applicationId, repository)` and a plain index on `repository` so "which Applications contain this repository" is cheap and multi-membership is expressly permitted. - `initiative_repositories` — `id`, `initiativeId` (cascade delete), `repository`, `origin` (`brief` | `operator` | `application` | `planner_suggestion` | `migration`), `sourceApplicationId` (nullable, `set null` on Application delete), `admittedByActor`, `admittedAt`; unique on `(initiativeId, repository)`. - `initiatives` gains `primaryRepository` (text, nullable), `applicationId` (uuid, nullable, `set null`), and `repositoryScopeState` (`unset` | `set`, default `unset`). - `run_event_kind` gains `scope_changed`; `audit_log` carries Application mutations with `entityType = "application"`. Application management - List Applications with name, key, description, owning team, member count and status; archived Applications are listed separately, not hidden. - Open an Application to see its repositories, each with registry status, frozen state, and the other Applications that repository belongs to. - Create an Application: key, name, description, optional owning team, and an initial repository selection drawn from the trusted registry. - Edit name, description and owning team; add and remove repositories. - Adding a repository not in the registry, or a frozen one, is refused with the reason stated in the picker before submission and re-checked at the service. - Archive an Application. Archiving hides it from selection while leaving every initiative that used it unchanged. Delete is permitted only when no initiative references it; otherwise the UI offers archive and says why. - A member that has since been frozen or removed from the registry is shown, marked, and excluded from scope population; startup validation reports it rather than deleting it. - Every Application shows which initiatives currently reference it. Initiative repository scope - The initiative detail page shows scope state, the associated Application if any, the primary repository, and every repository in scope with its origin, who admitted it, and when. - An initiative with `unset` scope shows a prompt to establish scope, and its planning affordances are disabled with the reason given. - Populate from an Application: selecting one previews exactly which repositories will be added, including any skipped for being frozen or absent from the registry, with the reason, before confirming. - Add a repository from the trusted registry. Ineligible repositories are shown with their reason rather than omitted, so "why can't I add this?" is answerable in the UI. - Remove a repository. If work items in a non-terminal state target it, the removal is refused and the UI lists those items with links, offers to open them, and asks the operator to resolve them first. The message is written for an operator, never surfaced as a constraint violation. - Set, change, or clear the primary repository. Removing the current primary from scope requires choosing another primary or explicitly clearing it, in the same interaction. - Scope suggestions appear inline with their evidence and Add to scope / Dismiss: a repository the planner named in its assumptions, a repository carried in `context.repositoryHints`, or one introduced by a brief commit. Dismissals persist in `initiatives.context.dismissedScopeSuggestions` — jsonb, so no table and no migration — and the planner is told on the next pass. - A repository in scope that is frozen or no longer in the registry is shown with a Blocked marker and the reason. Its work items stay visible and linked. Nothing new may target it, and the entry can be removed once the affected work is resolved — the same removal flow, with the same blockers. - Every change appears on the initiative timeline. Planning and work - The planner's catalog contains only in-scope repositories, with the primary marked, and carries the registry metadata it needs to reason about them — description, default branch, trusted validation keys, frozen state. - Continuation planning reads persisted scope; `continuationRepositoryHints()` is retired. - Roadmap candidate selection keys on scope rather than `repositoryHints`. - A plan whose item targets an out-of-scope repository is refused at persistence with a message naming the repository and the initiative's current scope. - A work item's `contract.allowedRepositories` must be a subset of the initiative's scope. - The plan editor's repository picker offers only in-scope repositories. - Filing a work item validates registry, frozen state and scope — closing the hole where it validates nothing. - Importing an issue, linking an epic, and declaring a related epic all validate scope in addition to their existing checks. - Materialization, PR creation and worker claim re-check scope, so an item persisted before enforcement cannot execute against a repository that is no longer permitted. - An initiative whose purpose is to create a repository admits that repository to scope from the registry before creation, exactly as `Xyence/www-xyence-io` is pre-registered today (#571). Canonical API - `GET /orchestrator/initiatives/{id}/repository-scope` — scope state, entries with origin and provenance, primary repository, associated Application, and per-entry removability with blockers. - `POST /orchestrator/initiatives/{id}/repository-scope/repositories` and `DELETE .../repositories/{repository}`. - `PUT /orchestrator/initiatives/{id}/repository-scope/primary` — set or clear. - `POST /orchestrator/initiatives/{id}/repository-scope/populate-from-application`. - `GET|POST /orchestrator/applications`, `GET|PATCH|DELETE /orchestrator/applications/{key}`, `POST|DELETE /orchestrator/applications/{key}/repositories`. - `GET /orchestrator/repositories` — the trusted registry catalog with frozen state and Application membership, so the Workspaces picker has a source that is not behind the engineering RBAC rule and the `REPOSITORIES_SURFACE_ENABLED` flag. - `canonicalInitiativeSummary` gains a compact `repositoryScope` (primary, count, Application key); the detail read carries the full scope. Workspaces operator app - Initiative detail: the scope panel and every mutation above. - `/initiatives/new`: an Application selector and repository scope step, with the brief's declared `repositoryScope` pre-proposed and requiring confirmation. - An Applications section: list, detail, and management. - Every repository selector that has an initiative in context is bound to that initiative's scope. - Enforcement - Creating a plan version with an item targeting an out-of-scope repository is refused, and the error names the repository and the current scope. - Filing a work item against a repository outside the registry, frozen, or outside scope is refused at the service, and via both `POST /orchestrator/initiatives/{id}/work-items/file` and `POST /api/initiatives/{id}/work-items`. - Xyence/orchestrator#610 is satisfied — closed independently before this initiative, or by its enforcement phase. Its acceptance criteria are not restated here; they are a precondition of this one. - Amending a work item's repository to an out-of-scope target is refused. - Importing an issue, linking an epic, and declaring a related epic from an out-of-scope repository are each refused. - A work item whose repository left scope cannot be claimed for execution, cannot have an issue materialized, and cannot have a PR opened. - A work item whose `contract.allowedRepositories` is not a subset of scope is refused at persistence. - Every refusal above is proven by a test that calls the service directly, not the route, and not the UI. Planner scoping - The catalog handed to the planner for an initiative equals its persisted scope; a registry repository outside scope never appears. - A synthetic planner output naming an out-of-scope repository is rejected on persistence, with the rest of the wave unaffected where the plan format permits. - Continuation planning for an initiative whose work touched a repository since removed from scope does not reintroduce it. - `repositoryHints` containing an out-of-scope repository grants no access and produces no work item. Applications - An Application cannot be created or edited to contain a repository outside the trusted registry. - The same repository can be added to two Applications, and both list it. - An initiative populated from an Application, then given an additional trusted repository not in that Application, is valid: the addition succeeds, planning proceeds, and no validation refuses it. - A member frozen or removed from the registry after admission stays listed on the Application, is reported by startup validation, and is skipped when that Application populates a scope. - Startup validation reports any Application member missing from the registry, the way bundle validation already does. - Removing a repository from an Application leaves every initiative scope that was populated from it unchanged. - Archiving an Application removes it from selection and changes no initiative scope; deleting one that an initiative references is refused with archive offered instead. Initiative scope - `primaryRepository` cannot be set to a repository outside scope. - Removing the primary repository from scope requires selecting a new primary or clearing it explicitly. - An initiative created without scope has `repository_scope_state = 'unset'` and cannot be planned; the refusal explains what to do. - An initiative with a deliberately empty scope is distinguishable from an unset one in the API and the UI. - Removing a repository with a non-terminal work item is refused and the response identifies those items. - Removing a repository whose only references are terminal succeeds, and no later operation re-adds it. - Every scope change writes a `scope_changed` event with the actor and the repositories affected. - A repository frozen after admission remains in scope, is marked blocked, and refuses new planning, filing, execution and GitHub actions; its existing work items remain readable and linked. - A repository removed from the trusted registry after admission behaves identically, and no migration, startup validation, or background process deletes the entry. - A blocked repository is absent from the planner's catalog and from Add-to-scope pickers, while still visible in the scope panel. Migration - Every existing initiative has a persisted scope, or `unset` with a reason recorded. - No repository whose only evidence is `context.repositoryHints` is admitted by the migration to any initiative. - An initiative whose only evidence is hints is left `unset`, and its trusted hints appear as scope suggestions. - The migration produces a report, runnable as a dry run, listing each initiative's derived scope, each entry's evidence, every hint-derived suggestion it declined to admit, and every initiative left `unset`. - Migrated entries whose only evidence is a committed brief declaration — no work item — are marked in the UI as needing review. - No initiative in a terminal state is blocked by migration. - Seeded Applications match the transcribed Hub manifest, minus any member absent from the registry, and each omission is logged. UI - Every operator capability in this brief is exercisable in the Workspaces app without an API client, and each has a UI test. - Repository pickers with initiative context offer only in-scope repositories. - An ineligible repository is visible with its reason rather than absent. - A blocked removal renders an operator-level explanation naming the blocking work, never a raw constraint error. Migration and compatibility behavior - Scope is migrated only from evidence that already represented an operational commitment: the repositories of the initiative's work items in any state, and the repositories its committed brief declares in `repositoryScope`. Both are intersected with the trusted registry, with the brief source repository removed. Entries are written with origin `migration` and actor `system`, and are individually reviewable and removable. - `context.repositoryHints` are **not** admitted. Hints have never been an authorization boundary — the planner prompt explicitly permits dropping them — so promoting a historical hint into a persisted permission would manufacture exactly the accidental expansion this initiative exists to prevent. Trusted hints that are not already in scope are rendered as migration-time scope suggestions, labelled as coming from historical repository hints, with Add and Dismiss. - Where an initiative's only evidence is hints, scope is left `unset` and the operator establishes the boundary. Where there is no evidence at all, it is likewise `unset` rather than guessed. Non-terminal initiatives in that state block planning with an explanation; terminal initiatives are recorded and never blocked. - `primaryRepository` is backfilled only where unambiguous — a single candidate, or a repository the committed brief names as primary. Otherwise it stays null. - `context.repositoryHints` is retained with a narrowed meaning: descriptive planner context that grants nothing. The brief-commit overwrite at `apps/web/src/app/api/initiatives/[id]/brief/commit/route.ts:39` remains, and a commit naming a repository outside scope produces a scope suggestion rather than widening anything. - The brief's `sections.repositoryScope` is retained as declared intent. At intake it proposes scope entries; admission stays explicit, and intake reports declared repositories it could not admit — the same "report what was discarded" contract as #488. - `deriveInitiativeRepositoryScope` and `expectedRepositoriesFromBriefScope` are retained: the first as a display classifier over persisted entries, the second for intake proposals. Neither remains a source of truth. - `/applications` and `/applications/repositories` switch to the persisted catalog. `loadTopologyManifest` stays for the repository-relationship view and becomes the import source once repaired; no runtime scope decision reads it. - `RELEASE_BUNDLES` is untouched, and its single-membership validation is explicitly not applied to Applications. - Canonical serialization gains fields only. `workItemCount`, `brief`, `state` and every other existing field keep their meaning. - Two sources of truth do not persist: after migration, derivation-from-hints is removed from every decision path in the same change that introduces the persisted read. ## Open questions - None outstanding. Two questions raised during review were settled rather than left open: an initiative references at most one Application in V1, and convergence with the Application Platform's created-Application lifecycle is later architectural work. Neither changes what must be built now, and neither should hold up planning.
8/25/2026DRAFTInitiative Brief: Instantiate the business website on the Application Platform
# Initiative Brief: Instantiate the business website on the Application Platform ## Desired outcome Use the Application Platform that already exists to create, deploy and populate the real business website: `Xyence/www-xyence-io`, serving a preview at `www.staging.xyence.io`, with the Articles from the current `www.xyence.io` migrated into it and manageable through Content Workspace and Composer. This initiative EXECUTES. It builds no new platform capability. Where something is missing it is a gap discovered by running the thing, and the smallest change that unblocks execution is the right one. The business website runs as an Application created by the platform. Its Articles are owned by that Application, edited through Composer and Content Workspace, previewed on `www.staging.xyence.io`, and published within the new application — while `www.xyence.io` continues to serve the existing site untouched. Every criterion is judged by the assembled system doing the thing, not by a component that could do it. ## Motivation The Application Platform Foundation initiative ran six waves and reached its wave cap. It delivered platform ADRs, topology manifest extensions for Application provisioning, an Application Template registry with a Public Web Application scaffold, a GitHub repository creation and scaffolding service, Hub manifest PR generation, a feature-flagged Create Application flow, a Doorway registration API with credential rotation through AWS Secrets Manager, a provider-boundary content client, Content Workspace provider-boundary Articles management, a one-time Articles migration tool, provider conformance smoke tests, and a V1 readiness checklist. Its brief assessment then found nineteen criteria unmet, and every one of them is an outcome rather than a component: "a new Public Web Application can be created through the Orchestrator Application Platform", "the business website's Articles are owned by the business website Application", "www.staging.xyence.io serves the new application's preview site". The assessment's own summary: *"The repository shows plans, harnesses, UI, docs, and tests, but not the executed creation and deployment of the www-xyence-io application, its app-owned provider and database, preview site at www.staging.xyence.io, or completed article migration. Where criteria require the assembled system to function (not just component correctness), evidence stops at scaffolds, specs, and dry-run artifacts."* `Xyence/www-xyence-io` does not exist. `Xyence-sandbox` contains only a `hub` repository, so even the sandbox demonstration has never run. Six waves of building were never followed by a wave of using. That is why this is a separate initiative rather than a seventh wave. The foundation is not in question; what is untested is whether it works when run. ## Current state - **The Create Application flow exists and is feature-flagged off.** `APPLICATION_CREATE_FLOW_ENABLED`, `APPLICATION_CREATE_FLOW_DRY_RUN`, `APPLICATION_REPOSITORY_CREATION_*` and `HUB_MANIFEST_*` are all unset on the box, so it resolves to disabled/preview and writes nothing. - **Dry-run is all-or-nothing.** The flow's dry-run state is the OR of the repository and Hub sub-services, forced together from the master flag, so a sandbox execution creates a real repository AND opens a real Hub PR. - **The flow can use its own GitHub identity** (`APPLICATION_CREATE_GITHUB_APP_*`, Orchestrator v0.4.22), so a sandbox run no longer has to repoint the platform's installation. - **No GitHub App currently holds the `administration` permission** that creating a repository requires. Both installations — `Xyence` and `Xyence-sandbox` — carry contents, pull_requests, issues, actions and metadata only. This is an operator prerequisite, not development work. - Doorway registration and credential rotation exist; credentials belong in AWS Secrets Manager under the platform's own prefix, never routed through OutShine. - Content Workspace provider-boundary Articles management is enabled by default for eligible Applications, with app scoping through Hub and a provider health indicator. - A one-time Articles migration tool exists and has never been run against real content. - `www.staging.xyence.io` resolves to the host the application will run on. `www.xyence.io` serves the existing production site. ## Architectural principles - The platform is the subject under test. Every step that could be done by hand should be done through the platform instead, because the initiative's whole value is discovering where it does not work. - A gap found by running is worth more than a gap found by reading. Where execution reveals a missing capability, record it as evidence rather than treating it as a plan defect. ## Rejected / deferred alternatives - Production cutover of `www.xyence.io`. - Images and media for Articles — storage, URLs and their migration. - Richer Composer authoring (WYSIWYG, media pickers, search). - A generalized page CMS or universal content schema; V1 supports Articles only. - New platform capability beyond what execution proves is missing. ## Constraints - Do not change what `www.xyence.io` serves. Production cutover is a separate, explicitly authorized operator step outside this initiative. - Do not build new platform capability. If execution is blocked, prefer the smallest change that unblocks it, and record what was missing. - Do not create the application by hand. Creating it outside the flow would prove nothing about the platform and is the one shortcut that makes this initiative pointless. - The sandbox demonstration precedes the real creation. Sequence it first. - PostgreSQL only. No object storage: Articles migrate text-only for V1. - Credentials go to AWS Secrets Manager under the platform's own prefix, never routed through OutShine to store them. ## Repository scope - `Xyence/orchestrator` - `Xyence/hub` - `Xyence/outshine` - `Xyence/workspaces` - `Xyence/www-xyence-io` — created by this initiative ## Expected behavior - The Create Application flow is demonstrated end to end in dry-run, and then in one sandbox execution under `Xyence-sandbox`, with the created repository, its scaffold and the Hub manifest PR inspected before any real application is created. - Sandbox artifacts are deleted after each run, so every demonstration exercises creation rather than the adoption path an existing repository takes. - `Xyence/www-xyence-io` is created through the flow — not by hand — with its scaffold and its Hub manifest PR. - The Application receives an application-owned PostgreSQL database and explicitly exposes an Article Content capability. - A Doorway registration is issued for it, its credential stored in AWS Secrets Manager under the platform's own prefix. - The application is deployed through the Application lifecycle and `www.staging.xyence.io` serves its preview site. - Articles from the current `www.xyence.io` are migrated with their metadata, including author and date. - Content Workspace discovers and manages those Articles; Composer creates and edits drafts. - A draft renders through the preview site and does NOT appear publicly; publishing makes it appear on the new application's production surface. - Routes are managed through the Application lifecycle rather than configured by hand. - The V1 readiness checklist and provider conformance smoke tests pass against the created application. ## Open questions - Which GitHub App gains the `administration` permission, and is it a new App scoped to application creation or the existing platform App? A separate App keeps repository-administration rights off the platform identity; the platform App is one permission change away. This is a prerequisite for any real or sandbox creation. - Should the sandbox demonstration run once and be deleted, or should a sandbox application be kept for future flow changes to test against? - Which Articles from the current site are in scope — all of them, or a selected set? The previous brief's answer said the Articles on the current site; a count and a source of truth would make the migration verifiable.
8/20/2026EXECUTINGInitiative Brief: The controller decides what the operator should do next
# Initiative Brief: The controller decides what the operator should do next ## Desired outcome An operator looking at a held initiative should be told what to do next by the Orchestrator, in the Orchestrator's own words, and should be able to act on it without inferring anything. Today the controller computes everything needed to reach that answer and publishes none of it, so the workspace infers an action from raw booleans — and gets it wrong in the ordinary foundation-first case. This initiative moves the "what now" decision into the controller, alongside the closure verdict that already lives there, and reduces the workspace to rendering it. An operator on a held or in-progress initiative sees one recommended next action, decided by the controller, with the controller's reason for it. Destructive actions are never the recommendation. The workspace renders that decision and derives nothing. Concretely: on the Composer initiative as it stood, the panel says "ready to plan wave 2", not "held — force-close planning". ## Motivation The Composer Initiative Tools initiative finished its first wave with all work complete, its continuation decision answered, and `continuationReady` true. Its next step was to plan wave 2, which would deliver the three capabilities its brief revision was written to add. What the operator was shown instead was a panel headed "This initiative is held", listing "3 deferred-scope entries undisposed" and "Planning is still open", with two suggested next actions: dispose the deferred scope, or **force-close planning (waives 3 entries)**. Neither mentioned planning the next wave. The operator asked, reasonably, whether force-closing would prematurely end the initiative. It would have: it would have waived the in-initiative read surface, the conversational mutations and the citation approach — the entire remaining substance of that initiative — and moved it toward completion having recorded that its own goal was an accepted gap. The state was healthy. The presentation was not. An operator who trusted the interface would have destroyed scope they had asked for one screen earlier. ## Current state - `canonicalPlanningStatus` serves `planningStatus`, `planningClosed`, `closure.{canClose, blockingCount, blockers}`, `deferredScope[]`, `continuation` and `hasProposedWave`. Every input needed to decide the next action is present; the conclusion is not. - `apps/orchestrator/src/lib/heldState.ts` in `Xyence/workspaces` derives the action itself: `const forceOnly = planning.canForceClose && !planning.canClose`, then offers force-close or close. Planning the next wave is not in that expression, so it can never be recommended. - `planningStatus` is a bare `"open"`. Open because more work is coming and open because something needs disposing are indistinguishable, and the panel calls both a blocker. - `held` is computed as "there is at least one blocker", so an initiative with more waves coming is reported as held. - The pattern this initiative wants already exists elsewhere: `availableActions` in `packages/db/src/services/recovery.ts` has the controller decide which actions its state permits and serve them, rather than leaving a client to infer them. - Issues #232 and #466 already corrected this class of mistake for other values — the client must never be the source of a decided value, and planning-status carries the closure verdict so the workspace does not recompute it. The completion path's *action* is the last decided value still being derived client-side. ## Architectural principles - The API owns the decided presentation state and the workspace only renders it. This is the same correction as #466 applied to the last value in the completion path still escaping it. - One computation, not two that agree by coincidence. The precedence rule lives in the controller next to the state it reads, so the affordance the workspace shows and the transition the controller would permit cannot disagree. - Follow the shape that already works: `availableActions` in the recovery path is the precedent for a controller serving actions from state. ## Rejected / deferred alternatives - Any change to what close, force-close, dispose, retract, defer-and-file or plan actually do. - The brief-assessment view model and its holds. - Redesigning the held-state panel's visual presentation beyond rendering the new fields. - Extending this to work-item or release-plan surfaces, which have their own action models. ## Constraints - Do not change what any action DOES. This initiative changes what the operator is told, not what close, force-close, dispose or plan actually perform. - Do not remove force-close, or make it harder to reach for an operator who has decided on it. It exists for a real case; it was simply never the recommendation. - Additive to the read model. Existing fields keep their meaning and their consumers keep working, so no client is forced to change in lockstep. - The controller decides; the workspace renders. No new derivation may be introduced client-side, including "helpful" fallbacks when a field is absent. - Do not fold the brief-assessment gate into this. Assessment already has its own view model and its own holds; this is about planning. ## Repository scope - `Xyence/orchestrator` - `Xyence/workspaces` ## Expected behavior - The canonical planning-status read model carries a controller-decided `nextAction`: what the operator should do now, with a label and the controller's own rationale. - The precedence the controller applies, and owns: a proposed wave awaiting review comes first; then an unanswered continuation decision; then planning the next wave when continuation is ready and scope remains deferred; then closing planning when closure is permitted; then disposing deferred scope. - Force-close is never served as `nextAction`. It remains available and reachable, as an explicit operator choice, never as the system's recommendation. - The model carries `availableActions` — everything the current state legitimately permits — so the workspace can offer secondary paths without inventing which ones exist. - Every action the model serves carries whether it is destructive, so a scope-waiving action cannot be rendered with the same weight as an ordinary one. - `planningStatus` distinguishes why planning is open: awaiting a next wave, awaiting disposition, or ready to close. - `held` means "cannot proceed without the operator", not "not yet complete". An initiative between waves with a clear next step is in progress, not held. - The workspace's held-state view renders the controller's `nextAction` and `availableActions` instead of deriving them from `canClose`/`canForceClose`. - The existing planning-status consumers keep working: the change is additive, and no field they read changes meaning. ## Open questions - Should `nextAction` ever be absent — for example on a closed, completed initiative — or should it always carry something, with an explicit "nothing to do" kind? An always-present field is easier for a client to render; an absent one is harder to render wrongly. - Should `availableActions` include actions the operator's capability does not permit, marked as unavailable, or omit them? Showing them explains why an affordance is missing; omitting them avoids advertising what cannot be done. - Does the brief-assessment hold need the same treatment, and if so is it this initiative or a later one?
Ready to release8/19/2026COMPLETEDInitiative Brief: Application Platform Foundation & Content Management V1
# Initiative Brief: Application Platform Foundation & Content Management V1 ## Repository scope - Repositories remain explicit engineering resources but should not be the primary abstraction exposed to ordinary application managers. - Orchestrator must surface repository relationships sufficiently for administrators/developers to understand and operate them. - ---
8/16/2026EXECUTINGComposer Initiative Tools: List/Count and Create from Brief
# Composer Initiative Tools: List/Count and Create from Brief ## Desired outcome An operator should be able to remain in a Composer conversation and naturally perform workflows such as: * “How many initiatives do I have?” * “List the current initiatives.” * “Which initiatives are still active?” * “Draft an initiative brief for what we just discussed.” * “Create that as a new initiative.” For read requests, the Composer should obtain current initiative data rather than infer it from conversation history or page context. For creation requests, once the operator explicitly asks to create/save the initiative, the Composer should invoke the canonical Orchestrator initiative-from-brief workflow and return the resulting initiative identity and status. The conversational surface should therefore be able to move cleanly from discussion → brief drafting → explicit creation without requiring the operator to copy and paste the brief into the Initiatives UI. ## Rejected / deferred alternatives - This initiative does not attempt to expose the complete Orchestrator control plane to the Composer. Unless required by implementation mechanics, defer conversational tools for: - editing or revising existing initiatives - cancelling initiatives - submitting initiatives for planning - starting or controlling execution - manipulating work items - release planning - arbitrary Orchestrator mutations - sophisticated initiative search/filter/query syntax Those capabilities can be added deliberately as separate runtime tools after the read/write pattern established here has been exercised. ## Constraints - Do not add duplicate initiative database services. - Do not add a parallel Initiative Brief parser. - Do not bypass the canonical Orchestrator initiative-from-brief endpoint. - Do not move Orchestrator-specific business logic into the shared Composer UI component. - Do not let model-supplied scope replace authenticated server-derived scope. - Keep the initial read surface focused on reliable initiative enumeration/counting rather than designing a general-purpose initiative query language. ## Repository scope - `Xyence/workspaces` - `Xyence/orchestrator` only if a small controller-side change is demonstrably required to expose an existing operation safely; do not duplicate APIs or domain behavior already present there. ## Expected behavior - Add a `list_initiatives` runtime tool — Expose an agent-callable, read-only tool for retrieving initiatives visible to the current authorized Orchestrator workspace context. The implementation should reuse the existing Workspaces/Orchestrator initiative read path. The result should be structured for reliable model use and include at minimum: - authoritative total initiative count - initiative ID - title - lifecycle/status information already returned by the canonical initiative list - any other existing canonical summary fields useful for distinguishing initiatives The tool must support both: - listing initiatives, and - answering count questions without requiring the model to estimate or derive a count from incomplete conversational context. Do not create a separate count endpoint merely for this use case unless an actual scale/performance requirement makes it necessary. The count can initially be derived authoritatively from the complete canonical list returned by the existing service. - Add a `create_initiative_from_brief` runtime tool — Expose an agent-callable mutation tool that creates a new initiative from Initiative Brief markdown. It should use the existing canonical initiative-from-brief workflow rather than directly inserting an initiative row. Creation must preserve the behavior of the existing canonical operation, including: - parsing the Initiative Brief - creating the initiative - creating and committing the brief revision - carrying repository scope/context into the initiative where applicable - returning validation failures - returning/reporting unrecognized brief headings rather than silently discarding content The tool result should include enough structured information for the Composer to confirm successful creation, including at minimum: - initiative ID - title - resulting initiative status - committed brief revision/status - any warnings such as unrecognized headings Where practical, also return sufficient information for the UI to link or navigate to the newly created initiative. - Treat creation as an explicit mutation — Drafting a brief and creating an initiative are distinct actions. The runtime must not create an initiative simply because it generated Initiative Brief text. Examples: - “Draft an initiative brief” → produce the brief only. - “What would an initiative for this look like?” → produce/discuss a brief only. - “Create this as an initiative” → invoke the creation tool. - “Save that initiative” after a brief has been drafted → invoke the creation tool. Use the platform's existing mutation confirmation/authorization conventions where applicable. Do not introduce a Composer-specific permission model. - Preserve server-authoritative scope and authorization — Neither tool may trust model-supplied organization, workspace, user, or permission information. Authorization and scope must come from the authenticated server-side runtime/session context and the existing Orchestrator control-plane authorization path. A conversation must not be capable of reading or creating initiatives outside the initiatives available to the current user/workspace context merely by supplying different IDs or scope values in tool arguments. - Integrate tools into the conversational runtime — Register the tools where workspace-specific runtime capabilities are assembled so that the Orchestrator Composer can discover and invoke them. Do not embed Orchestrator business logic into the shared visual `Composer` component. The Composer remains a platform-owned input surface; workspace-specific tool availability belongs at the conversational runtime/capability boundary. Tool execution and results should participate in the existing conversation provenance model so an operator can tell when the assistant's answer was grounded by `list_initiatives` or resulted from an initiative-creation action. - Handle mutation retries safely — A failed/retried conversational turn must not accidentally create duplicate initiatives. Use the existing request/message idempotency mechanisms where they can safely cover tool execution. If they do not currently protect mutations performed inside a runtime turn, introduce the narrowest appropriate idempotency mechanism for `create_initiative_from_brief`. The system should be able to distinguish: - an unsuccessful create that may safely be retried, from - a create that succeeded but whose response was interrupted or lost. - Return actionable failures — Tool failures should be represented structurally to the runtime rather than reduced to generic prose. At minimum distinguish: - authorization/permission denial - invalid Initiative Brief or controller validation failure - controller/service failure - ambiguous creation result where the controller may have accepted the write The assistant should be able to explain the failure without inventing a result or encouraging a blind retry that could duplicate an initiative. - Asking the Orchestrator Composer “How many initiatives are there?” causes it to invoke `list_initiatives` and return the exact current count. - Asking it to list initiatives produces information based on the live canonical initiative list rather than conversation history. - An empty initiative collection correctly returns a count of zero. - The list tool observes the same authorization and workspace scope as the existing Orchestrator UI. - Asking the Composer only to draft an Initiative Brief does **not** create an initiative. - After a brief has been drafted, an explicit request such as “Create that initiative” invokes `create_initiative_from_brief`. - Successful creation produces an actual Orchestrator initiative with a committed Initiative Brief using the existing canonical creation path. - The assistant receives and reports the created initiative ID/title and resulting brief status. - Validation errors and unrecognized headings remain observable. - Unauthorized creation is refused by the existing authorization boundary. - Retrying a turn after an uncertain transport/runtime failure does not create duplicate initiatives. - A newly created initiative is visible on the subsequent `list_initiatives` call. - Tool invocation/provenance is visible through the existing conversation-runtime provenance mechanism. - Automated tests cover empty and populated lists, count accuracy, successful creation, validation failure, authorization denial, creation warnings, and retry/idempotency behavior.
Ready to release8/16/2026COMPLETEDThe completion path on the canonical surface: finish an initiative from the workspace
# The completion path on the canonical surface: finish an initiative from the workspace ## Desired outcome An operator takes an initiative from "all work items done" to COMPLETED without leaving the workspace UI. When an initiative is held, the workspace says exactly what holds it — open planning, undisposed deferred scope, an unanswered continuation decision, a running assessment, a holding verdict — and every blocker names the action that clears it. Disposing deferred scope, closing planning, answering a continuation decision, discarding a proposed wave, re-running the assessment, and clearing a holding verdict (waive or attest) are all workspace actions. Nobody has to open the standalone UI, query the database, mint a token, or run the plan CLI to learn why an initiative still shows Active. ## Motivation Two initiatives just finished every work item and then sat in EXECUTING, indistinguishable in the workspace from initiatives still working. Diagnosing and resolving them took direct database queries, internal `/api/*` calls with a hand-minted admin JWT, and the plan CLI on the production box — for what turned out to be routine operator decisions: dispose six deferred-scope entries, answer two continuation checkpoints, close planning, waive one assessment criterion that pointed at deliberately deferred work. None of that was a malfunction. The gate behaved as designed at every step. The problem is that the design is invisible from the workspace: the canonical surface was built for the happy path (create → brief → plan → approve → execute) and the completion path never got routes. The workspace is the platform's UI going forward — the standalone UI is now legacy-frozen — so an initiative's ending must be as operable from the workspace as its beginning. ## Current state - `canonicalWave` serializes wave/state/summary/eligibility/items and **drops `deferredScope`, `continuationCheckpoint`, and `closesPlanningIfApproved`**. No canonical route carries `planningStatus`. The workspace cannot render what it is never sent; its app code has zero occurrences of any of these concepts. - Canonical wave actions are list, approve, and generate/continue (POST to the collection, pass chosen server-side from state). **Close planning, reopen planning, answer a continuation decision, retract a deferred capability, and discard a proposed wave exist only on the internal `/api/*` surface.** - **Defer-and-file has no HTTP surface at all.** It is plan-CLI only, requires `DATABASE_URL` plus a `ROADMAP_DIR` checkout, and writes roadmap markdown into the orchestrator repo — so filing RM-0006…RM-0012 each required a CLI run on the box plus a hand-made PR. The roadmap services already go through a `RoadmapPort` abstraction (`deferAndFileNew(db, port, input)`), so the store behind it is swappable. - **The brief-assessment gate has no canonical surface.** The pending/running/holding/delivered view, waive-criterion, attest-criterion, and reassess exist only internally. The domain already exposes `deriveBriefAssessmentView` as a server-decided view model — documented as existing precisely so clients render the same verdict — but no canonical route serves it. - The one completion signal the workspace does receive — release-readiness blocker "initiative planning is still open" — names the state, not the cause (which entries block and why), offers no action, and sits under Release Readiness where nobody looks while asking "why is this initiative still Active?" - The standalone UI has all the affordances (deferred-scope list with disposition labels, Close/Force-close, ContinuationDecision, BriefAssessmentPanel with a self-refreshing running state), because it bypasses the canonical surface and reads the database through internal routes. It is legacy-frozen; nothing new lands there. - Assessment runs are observable in principle (`brief_assessment_run_started_at` plus a single-flight staleness window); the running/pending states exist in the domain view model. - The roadmap store of record today is git-backed markdown (`roadmap/RM-XXXX-*.md`, currently RM-0001…RM-0012) in the orchestrator repo, read via `RoadmapStore` over `ROADMAP_DIR`. - orchestrator#457 (fixed): retraction and force-close now record dispositions the closure gate honors. The only remaining pre-fix row (retracted, null disposition) sits on a SUPERSEDED plan of the completed Composer initiative, where no gate reads it; no live initiative carries one. ## Product principles - A held initiative explains itself: every blocker is visible where the operator is already looking, states its cause, and carries its action. - Same verdict everywhere. The workspace and the gate must agree, because the workspace renders the same server-decided view the gate evaluates — never a client-side re-derivation. - Waiver and attestation remain opposite records (an operator accepting a gap vs. affirming work was performed) and must be presented as such, never as one "clear" button. - Destructive or scope-losing actions (force-close waiving remaining entries; discarding a proposed wave) are explicit, named, and confirmed — not the default path. - A long-running assessment shows that it is running; the operator never reloads to find out. ## Architectural principles - The canonical `/orchestrator/*` surface is the contract clients are written against; the workspace consumes only it. Closing the gap means extending that contract, not teaching the workspace to reach around it. - Server-decided view models: canonical routes serve the existing domain derivations (`deriveBriefAssessmentView`, `canClosePlanning`/`unresolvedDeferredScope`, release-eligibility reasons) rather than raw rows the client must interpret. - The database is the roadmap's source of record; markdown is a generated export view, never hand-authored. Roadmap access stays behind the existing `RoadmapPort` so the CLI and services swap stores without changing callers. - Actor is server-derived from the verified platform token (ADR-0007); two-tier RBAC as on the rest of the canonical surface (reads member, mutations admin). - Mutations are idempotent under retries (the existing `requestId` pattern) and every one lands in the timeline with its actor and reason. - The dispositions vocabulary (#361/#363/#457) is the single source of truth for what blocks closure; no new parallel flags. - Work splits by repository along the contract line: Xyence/orchestrator — roadmap store migration (DB persistence behind `RoadmapPort`, one-time markdown import, cadenced markdown export back into `roadmap/`); canonical routes and view models for planning status, deferred scope with per-entry disposition and blocking flag, close/reopen planning, answer continuation decision, retract, defer-and-file, discard proposed wave, waive/attest criterion, reassess, and a served brief-assessment view including the running state. Every one of these actions already exists internally or in the CLI; reuse the services. Xyence/workspaces — render the held-state explanation on the initiative page (not only under release readiness); deferred-scope list with dispositions and actions; continuation-decision prompt; discard affordance on a proposed wave; assessment panel with pending/running/holding/delivered states, waive/attest, and a reassess action, self-refreshing while running. Xyence/console — none expected (gateway proxies verbatim). ## Decisions - The roadmap store of record moves into the database, with markdown as a generated export — the existing roadmap files RM-0001 through RM-0012 are the one-time import seed, RM ids remain stable, and this is what makes a canonical defer-and-file action possible (the controller cannot commit to the git repo; the store move removes the need to). - Wave discard joins this initiative — the internal discard action gets a canonical equivalent and a workspace affordance, so a proposed wave can be rejected with a recorded reason from the workspace, not only approved. - Workspace-triggered reassessment is in scope — the operator can re-run the brief assessment from the workspace, subject to the existing single-flight slot; a run already in flight is reported, not duplicated. - The standalone UI is legacy-frozen — no parity fixes land there; the completion path is built once, on the canonical surface, rendered by the workspace. - The markdown export lands back in the repo on a cadence — a generated roadmap snapshot, clearly marked as generated and never hand-edited; the export is asynchronous and never in the critical path of any workspace action, and a filing that succeeded is durable in the database whether or not the next export has run. - Roadmap promotion gets a workspace affordance in a later wave, not this one — plan import and roadmap-status stay CLI-only for now; this is deliberately deferred scope, not an omission, and should be planned as such. - Deferred scope keeps gating planning closure — a terminal disposition is retracted, waived, or durably-filed-deferred with a roadmap id and captured flag; this gate stays. - The brief assessment keeps gating completion — waive and attest remain the two operator paths to clear a holding criterion; this gate stays too. - New canonical actions follow the established POST-to-collection pattern where the server picks the pass from state — the model wave generation already uses; state decides, not client flags. ## Rejected / deferred alternatives - Having the workspace call the internal `/api/` surface directly — that surface is the standalone UI's private plumbing with no contract stability. - Keeping the roadmap store git-backed with the controller opening PRs via its GitHub App credentials — rejected in favor of the database store because a completion action must not depend on a PR merging; the cadenced markdown export is different, being a snapshot off the critical path whose late landing blocks nothing. - Auto-closing planning when the last work item completes — closure is an operator decision precisely because deferred scope may still need disposing; the fix is visibility and reachable actions, not automation that silently waives. - Auto-waiving assessment criteria that match filed roadmap items — the waiver is the operator's judgment; the UI may suggest the linkage. ## Constraints - Single production box; the workspace app and controller stay separate containers speaking HTTPS with the existing service JWT and roles claim. - The roadmap-store migration must import RM-0001…RM-0012 without renumbering — dispositions in live initiative rows link to these ids (`roadmapItemId`), and those links must survive. - The plan CLI keeps working through the migration (re-pointed at the DB-backed port), since it remains the only tool for bulk operations like `import` and `promote` until those get surfaces. - Console gateway proxies the relevant subtrees verbatim; no Console work expected. - Existing internal routes and the standalone UI keep working unchanged throughout; this is additive to the contract. ## Invariants - No initiative can reach COMPLETED with an undisposed deferred-scope entry or an uncleared holding assessment — unchanged. - Every disposition, closure, waiver, attestation, and wave discard records its actor and reason in the timeline. - The closure gate is evaluated from dispositions only; anything the workspace displays derives from the same evaluation the gate uses. - Roadmap RM-ids are stable across the store migration; a `roadmapItemId` recorded before it resolves after it. - No credential reaches the workspace client; canonical mutations remain admin-tier. ## Repository scope - Xyence/orchestrator - Xyence/workspaces - Xyence/console ## Expected behavior - An initiative whose work is done but which is held shows a single, prominent explanation on its workspace page: what holds it, why, and the buttons that resolve it. - The deferred-scope list shows each entry's disposition (deferred-and-filed with its RM link, retracted, waived, still blocking) using the same vocabulary the gate uses. - Answering a continuation decision, retracting an entry, filing an entry to the roadmap, discarding a proposed wave, and closing planning are workspace actions with confirmation and recorded reasons; force-close is separate, named as a waiver of N entries, and confirmed. - Filing an entry to the roadmap creates the roadmap record directly — no CLI, no PR — and the entry immediately shows its RM link. - After closing planning, the page shows "assessment pending," then a visibly-running assessment, then the verdict — without a reload. The operator can re-run the assessment; a run already in flight is reported, not duplicated. - A holding verdict lists each unmet criterion with its evidence and offers waive (reason required) and attest (affirmation required) per criterion; clearing the last one completes the initiative immediately, visibly.
Ready to release8/16/2026COMPLETEDInitiative Brief: Consolidate Platform AI Agent Configuration Ownership
# Initiative Brief: Consolidate Platform AI Agent Configuration Ownership ## Desired outcome Establish a clear ownership boundary for platform AI configuration such that: * OutShine is the canonical backend owner of AI/runtime configuration used by platform and Workspace capabilities. * Console remains the administrative management surface for this configuration. * Workspace and OutShine runtimes do not depend on Console availability to obtain configuration. * Existing agent configurations are inventoried and classified before migration. * Obsolete configuration is deprecated or removed rather than automatically carried forward. * The transition preserves currently operating AI features without a flag day or unnecessary new infrastructure. ## Rejected / deferred alternatives - This initiative does not: - redesign every AI prompt; - select new models for every existing role; - rebuild legacy OutSold features merely because they have agent configuration; - migrate deferred features into their eventual Workspace modules; - create a standalone AI platform service; - redesign the Console Agent Configuration UX beyond changes required to support the new backend; - broadly reorganize other Console BFF responsibilities unrelated to AI configuration. ## Repository scope - Inventory the Current Registry — Produce an authoritative inventory of: - every `agent_configs` key seeded or migrated by Console; - every code path that reads each key; - the repository and subsystem executing that role; - whether the consumer is currently active; - whether the corresponding feature is expected to survive in the current platform architecture; - any environment-variable fallback or duplicate hardcoded configuration; - any metadata semantics specific to individual roles. Include both direct Console consumers and OutShine consumers using the internal configuration bridge. Known examples requiring classification include, but are not limited to: - conversation/runtime assistant configuration; - historical narrative generation; - ownership investigation; - property media caption generation; - document FAQ candidate generation; - video/script/narration roles; - other content, document, listing, artifact, album-analysis, Idea Studio, identity, and lead-related AI roles. Do not assume that presence in the existing table implies that a configuration should survive. - Classify Every Agent Role — Assign each existing role one explicit disposition: A. Platform / OutShine-Owned — Migrate — Use for AI roles executed by: - OutShine services; - the Workspace conversational runtime; - reusable platform capabilities; - domain/workflow services hosted by OutShine. These configurations move to OutShine and become canonical there. The workspace Composer `conversation_runtime` configuration must be included in this category. B. Console-Owned — Retain Locally — Use only when the AI capability itself genuinely belongs to Console rather than when Console merely provides its UI. Any item placed in this category must have an identified live Console-native consumer and architectural justification. Do not retain configuration locally simply because its administration currently lives under `/admin/agents`. C. Legacy / Deferred — Deprecate — Use for roles whose corresponding feature: - is no longer used; - is experimental or abandoned; - belongs to an older OutSold interaction model; - is expected to be replaced by a dedicated Workspace/module implementation; - has no identifiable live consumer. Do not migrate these records into the new canonical registry unless and until the corresponding capability is retained or rebuilt. Record enough information to recover historical intent if necessary before removing the configuration. - Add an OutShine AI Configuration Registry — Implement canonical AI-role configuration persistence in OutShine. The registry should support at least the currently required common fields: - stable key; - human-readable label; - provider; - model; - token/output limits; - temperature or equivalent generation settings; - system/base prompt where appropriate; - enabled/disabled state; - extensible metadata; - timestamps. Preserve stable agent keys wherever doing so avoids unnecessary consumer churn. Avoid encoding feature-specific semantics into the common registry unless they are genuinely common platform concerns. - Add OutShine Management APIs — Provide authenticated APIs for: - listing configurations; - retrieving a configuration by stable key; - creating/upserting configurations; - updating configurations; - enabling/disabling configurations; - validation of supported provider/model combinations as appropriate. Separate administrative mutation authorization from runtime read access. Internal OutShine services should access the underlying service/repository directly rather than making HTTP requests back into their own API. - Move Composer Conversation Runtime Configuration First — Treat the Workspace Composer conversation runtime as the first migration target. Remove the architecture in which OutShine resolves `conversation_runtime` by calling: `Console /api/internal/agent-configs/:key` Replace it with native OutShine configuration resolution. Preserve existing provider selection, caching, failure classification, feature-flag behavior, observability, and development/test safeguards unless there is a specific reason to change them. After migration, Composer conversation execution must not require `OUTSOLD_INTERNAL_BASE_URL` or Console availability. - Migrate Other Live OutShine Consumers — Replace the generic Console `agent_configs` bridge used by OutShine services with the new native registry. Inventory and migrate consumers systematically rather than changing only the Composer path and leaving the same inversion elsewhere. Where multiple services currently use the same Console-fetch helper, establish one canonical OutShine-side configuration service rather than creating feature-specific replacements. - Preserve Console as the Administrative UI — Retain the Agent Configuration management experience in Xyence Console. Refactor the Console BFF endpoints used by the admin UI so that they manage the OutShine registry rather than Console's local `agent_configs` table. From an operator's perspective, `/admin/agents` should continue to provide centralized management even though persistence has moved behind the platform boundary. The UI should clearly identify deprecated roles if they are temporarily shown during migration. - Transitional Compatibility — Avoid a flag-day migration. Provide a bounded compatibility period in which necessary legacy callers can continue functioning while individual consumers move. Preferred transition: - Add and seed/migrate the OutShine registry. - Move `conversation_runtime`. - Move remaining live OutShine consumers. - Change Console's Agent Configuration administration to proxy OutShine. - Verify no active runtime reads Console's local registry. - Remove the OutShine → Console agent-configuration bridge. - Remove obsolete Console persistence/API code once no consumers remain. Do not create indefinite dual-write behavior. If temporary synchronization is required, define a clear removal condition and make one side explicitly authoritative.
Ready to release8/15/2026COMPLETEDInitiative Brief — Make the Composer agent real: tool-calling over platform data
# Initiative Brief — Make the Composer agent real: tool-calling over platform data ## Desired outcome The workspace Composer answers real questions about the operator's own platform data — grounded in what the system actually holds, showing what it consulted, and safe by construction — instead of echoing the message back. Asking "why does this work item have RFC in the title?" returns an answer read from that initiative's work item, not a guess and not an echo. ## Motivation The Composer is the platform's primary conversational surface and the one users reach for first. Today every message returns `Acknowledged: <your text>`, because the runtime is running its deterministic offline provider. That is not an unfinished feature so much as an unfinished last mile. The foundation shipped: a server-side runtime with a bounded context window, a swappable provider adapter, a capability registry with per-action authorization, a confirmation flow for mutations with durable audit receipts, and redacted telemetry. Two things are missing, and neither is small: 1. The only provider that can emit tool calls is the **mock**. The real provider (`agent_text`) is text-only by design, so even switched on it cannot look anything up. 2. The capability registry ships **one stubbed read** and **one mutate placeholder**. There is nothing real for a provider to call. The result is a surface that looks finished and answers nothing. Closing this converts a demo into the platform's actual front door. ## Current state - The `conversation_runtime` feature flag is **enabled** in the production database. - `CONVERSATION_RUNTIME_PROVIDER=agent_text` is now staged in OutShine's prod `.env` but **not yet active** — it takes effect on the next restart/deploy. - No `agent_configs` entry keyed `conversation_runtime` exists in Outsold. Until it does, a send under `agent_text` raises `RuntimeProviderError` and **fails outright** — strictly worse than the mock's echo. The Outsold bridge URL and service token are both configured. - `AgentTextRuntimeProvider` is explicitly text-only: "it does not emit tool calls (the mock covers tool orchestration)". - `build_default_registry()` returns `workspace.read_summary` (a stubbed read) and `workspace.request_action` (a mutate placeholder that is never executed). - Bounds already enforced: 20 messages / 12,000 characters of context per turn, and a hard ceiling of 3 provider↔tool round trips per message. - The client/server conversation contract mismatches were fixed server-side (outshine #456, #459); send and history now work end to end. - The confirmation and receipt paths exist in code but have never been exercised end to end from the client. ## Product principles - Answer from the platform's own data, never from model memory. An ungrounded answer about an operator's initiatives is worse than no answer. - When the assistant cannot answer, it says so plainly and names what it would need. - Every mutation is explicitly confirmed by the user and leaves a durable receipt visible in the conversation. - The user can see what the assistant consulted to produce an answer. - A misconfigured backend produces an honest, actionable message — never a silent echo and never an opaque failure. ## Architectural principles - Provider credentials stay server-side and resolve through the Outsold `agent_configs` registry. No provider key belongs in a workspace app or in OutShine's own `.env`. - The server adapts to the client contract, not the reverse (the direction established in #394/#416/#417/#428 and applied again in #456/#459). - Context is always bounded. No unbounded transcript ever reaches a provider. - Capabilities authorize per-action against the caller's real permissions. Being in a conversation grants nothing. - The provider stays swappable behind the adapter; the runtime never depends on one vendor's tool-call shape. ## Constraints - Single production box with 7.6 GiB RAM shared by every service. Builds and deploys serialize; a careless build has frozen this box before. - CI must stay fully offline. The mock remains the default so no test ever reaches a provider. - Per-turn cost and latency must be bounded and observable before this is enabled for real traffic. - Message content must never enter logs; telemetry stays counts and low-cardinality labels. - The workspace Composer's existing UX contract (send, history, receipts) must not regress. ## Invariants - The default provider is the offline mock. - No provider credential reaches the client or the logs. - Every tool call is authorized against the caller's actual permissions at call time. - Every mutation produces a durable, user-visible receipt. - Context handed to a provider is always bounded by both message count and character count. ## Expected behavior - Asking about an initiative, work item, or release returns an answer read from that record, including its actual text. - The answer shows what the assistant consulted, so the user can verify it. - Asking the assistant to change something produces an explicit confirmation prompt, and after confirming, a receipt that survives a reload. - While the assistant is doing multi-step work, the Composer shows that it is working rather than appearing hung. - If the provider is misconfigured or unavailable, the Composer says so plainly and the message is preserved. ## Open questions - Which provider and model for the `conversation_runtime` agent config — and what is the acceptable per-turn cost? - Which read capabilities land first? Proposed order: initiatives and work items (the reported use case), then workspace directory, then releases and worker health. - Should Orchestrator reads go through the canonical `/orchestrator/*` HTTP surface or a service-to-service call with the existing workspaces↔orchestrator service JWT? - Who owns the cost ceiling and monitors it once real traffic starts? - Does the confirmation flow need a UX pass before mutating capabilities are exposed, given its client paths have never run end to end? - Should tool-call support be added to `AgentTextRuntimeProvider` or land as a third provider, leaving the text-only bridge untouched for other callers?
Ready to release8/15/2026COMPLETEDInitiative Brief: Outshine Application Platform & Orchestrator Evolution
# Initiative Brief: Outshine Application Platform & Orchestrator Evolution ## Repository scope - Repositories remain first-class engineering resources managed by Orchestrator. Orchestrator should surface: - Repository identity - Repository location - Associated Platform - Associated Application - Branch information where relevant - Working/deployment state - Agent accessibility Repositories should not become the primary abstraction presented to non-technical application managers. ---
Ready to release8/14/2026COMPLETEDInitiative Brief: Operator Feature Parity in the Workspaces Orchestrator App
# Initiative Brief: Operator Feature Parity in the Workspaces Orchestrator App ## Desired outcome The Orchestrator workspace app is the single place an operator does operator work. Everything reachable today only in the standalone control-plane UI — release planning and cutting, the operational dashboard, and the cross-initiative question queue — is available in the workspace app, consumed over the canonical `/orchestrator/*` API, authenticated as the real acting principal and scoped to an org and workspace. The standalone UI stays deployed. Its pages become a break-glass surface rather than the primary one, and it continues to host the control-plane API unchanged. ## Motivation Operator surfaces are split across two UIs with no rule about which gets new work, and the split is widening rather than closing. The release-management layer — the newest and largest operator capability built — landed entirely in the standalone UI, which was otherwise being treated as legacy. An operator now switches surfaces mid-task, and the workspace app cannot answer "what is being released?" at all. The cost is not only navigation. The standalone UI attributes every action to a single static operator identity and is reachable by anyone who can reach the host; the workspace app authenticates a real principal and scopes to an org and workspace. Work that matters — publishing a GitHub release, answering a blocking question — is better done where the record says who did it. ## Current state - The workspace app (`Xyence/workspaces`, `apps/orchestrator`) has: home, initiatives list and detail, brief revision, work-item detail, initiatives/new, workers list and worker detail. - The standalone UI (`Xyence/orchestrator`, `apps/web`) has: home, initiatives detail, initiatives/new, **`/ops`**, **`/questions`**, **`/release-plans`**, **`/release-plans/[id]`**, **`/releases`**, **`/releases/[id]`**. - Only the standalone UI has releases, ops and a cross-initiative question queue. Only the workspace app has worker pages and work-item detail. - `apps/web` is also the control plane: it serves 125 `/api/*` routes (worker claim, heartbeat, progress, GitHub webhooks, admin/ops JSON) and 21 `/orchestrator/*` routes. It cannot be removed; only its pages are candidates for removal. - The canonical `/orchestrator/*` surface today covers initiatives, waves, work items, questions **within one initiative**, release *readiness* for one initiative, and workers. It exposes **nothing** for release plans, release publishing, or the operational dashboard. - The standalone pages are server components that read the database directly (`getDatabase()`, `buildOperationalDashboard`, `listQuestions`). The workspace app is in a different repository behind an HTTP boundary and cannot do this; every surface it gains needs a canonical endpoint. - Approximate sizes: release UI ~1,220 lines across 7 components plus ~240 lines of pages; ops ~426 lines plus a 30-line page; questions ~112 lines plus a 232-line card component. - `/api/admin/ops/dashboard` already serves the same aggregation the ops page renders, so the ops surface is closer to a re-host than a rebuild. - Release mutations are the only genuinely new authorization surface: create, add initiatives, set repositories, prepare, edit notes, publish, retry, cancel, and target ordering — roughly fourteen endpoints, today answering as the static operator actor. ## Product principles - One operator UI for everyday work; the operator should never have to know which app owns a task. - No capability regresses during the migration. A surface appears in the workspace app before anyone is asked to stop using its counterpart. - Break-glass access survives. An operator must retain a way to act when platform auth or the Console gateway is unavailable. - Read-only surfaces can move quickly; anything that mutates production waits for real principal attribution. ## Architectural principles - The workspace app consumes `/orchestrator/*` over HTTP and never reaches the orchestrator database directly. - The controller adapts to the canonical contract, not the client. Vocabulary translation, status mapping and shape changes belong on the controller side, as established when the worker surface was made canonical. - New canonical endpoints are principal-scoped: the acting operator is derived from the platform session, not a static actor. - The canonical surface publishes an empty result distinctly from an absent one, so "nothing to show" and "not implemented" never look the same to a client. - No new credential surfaces. The workspace app reuses its existing authenticated, scoped API client. ## Domain concepts - **Workspace app**: `Xyence/workspaces`, `apps/orchestrator`; the Orchestrator workspace served at `orchestrator.workspaces.xyence.io`, authenticated and org/workspace scoped. - **Standalone control-plane UI**: `Xyence/orchestrator`, `apps/web` pages; the admin surface at `orchestrator.xyence.io`, attributed to a static operator actor. - **Canonical surface**: the `/orchestrator/*` API the workspace app is written against; the stable contract for automation and MCP intake as well as this frontend. - **Break-glass**: operating the platform when platform auth or the Console gateway is down. - **Release plan**: the publish lifecycle object (`/api/release-plans/*`); distinct from **release targets** (`/api/releases/*`), which drive deploys. ## Decisions - The standalone UI stays deployed for now; this initiative does not remove it. — Operator decision, 2026-08-14. - The workspace app is the operator UI going forward; new operator surfaces belong there. — Follows from the split this initiative exists to close. - `apps/web` remains the control-plane API host regardless of what happens to its pages. — It serves the worker endpoints, webhooks and the canonical surface itself. - Release *services* stay in `Xyence/orchestrator`. Only the operator interface moves. — The service owns the database and the GitHub integration. ## Rejected / deferred alternatives - Delete `apps/web` once the pages move. Rejected — it is the control plane, not just a UI. - Delete the standalone pages as each surface lands. Deferred, not rejected — break-glass has real value while the Console gateway is still proxying incompletely. Revisit when parity is complete and the gateway is sound. - Have the workspace app read the orchestrator database directly. Rejected — it is a separate repository and deployment; the HTTP contract is the boundary. - Move the release service code into Workspaces. Rejected — it owns the schema, the audit trail and the GitHub release integration. - Publish `@xyence/` packages to consume the shell from `Xyence/orchestrator`. Rejected for this initiative — the surfaces move toward the workspace app, not the reverse. ## Constraints - Two repositories change: `Xyence/workspaces` (the app and its API client) and `Xyence/orchestrator` (new canonical routes only — no page changes). - `.github/workflows/**` is a protected path in both repositories. - No new credentials, tokens or auth schemes; reuse the existing scoped client and platform session. - Existing standalone URLs keep working while the standalone UI remains deployed. - Release publishing acts on real GitHub releases; behaviour must not change as a side effect of exposing it canonically. ## Invariants - A publish, retry or cancel performed from the workspace app records the real acting principal, never a static operator actor. - Backend authorization stays authoritative: the workspace app renders what it is allowed to see, and never decides access itself. - Partial-failure semantics of release publishing are preserved exactly — per-repository outcomes, `retryable` classification, and retry that skips what already published. - No workspace-scoped surface leaks data across orgs or workspaces. - Nothing in this initiative alters the worker protocol, the review gate, or deploy behaviour. ## Repository scope - `Xyence/workspaces` — `apps/orchestrator` (pages, components, nav), `packages/api-client`. - `Xyence/orchestrator` — `apps/web/src/app/orchestrator/**` (new canonical routes), `apps/web/src/server/**` (projections). No changes to `apps/web` pages. ## Expected behavior - An operator opens the Orchestrator workspace and sees release plans: their state, participating repositories, pinned commits, notes and per-repository publish outcomes. - Preparing, editing notes, publishing, retrying a failed publish and cancelling are all possible from the workspace app, with the acting operator recorded. - An operational dashboard shows component health, worker presence, current executions and active incidents, matching what the standalone `/ops` page shows today. - A single queue lists every open question across initiatives, and answering from it behaves exactly as answering from within an initiative does. - The standalone UI continues to work unchanged throughout. ## Open questions - Should release mutations require an admin role, or is any workspace member with access sufficient? The canonical auth layer already distinguishes admin from viewer. - Should the operational dashboard be visible to any member, or restricted to admins? It exposes worker identities, incidents and execution state. - Is the cross-initiative question queue a workspace-scoped view, or genuinely global? Questions belong to initiatives, which belong to workspaces. - How long does break-glass remain? Naming a condition for retiring the standalone pages — rather than a date — would keep the decision honest.
Ready to release8/14/2026COMPLETEDInitiative Brief: Canonical Workspaces Host Architecture and Complete Orchestrator Shell Integration
# Initiative Brief: Canonical Workspaces Host Architecture and Complete Orchestrator Shell Integration ## Desired outcome Establish and enforce a canonical Workspaces host architecture that fully composes platform-owned workspace facilities, then migrate the Orchestrator workspace onto that architecture without rewriting its existing routing or domain topology. After this initiative: - Workspaces provides a clear, reusable, documented composition path for platform-owned workspace facilities. - Workspace implementations contribute domain UI, declarative navigation, semantic context, capabilities, and other workspace-specific data rather than reconstructing shared shell behavior. - Orchestrator consumes the real platform navigation/menu rail, conversation history, Composer, attachments/screenshots, runtime integration, confirmation/audit UX, responsive behavior, and other applicable shared Workspaces facilities. - The existing Orchestrator placeholder conversation/Composer regions are removed. - Future workspace implementations, including Web, have an authoritative architectural path that strongly discourages or prevents ad-hoc replacements for platform facilities. This initiative must **not** be interpreted as an instruction to rewrite Orchestrator onto canonical Sales routing, convert it to the Sales module topology, or migrate its URLs to `/w/:workspaceId/*`. The goal is canonical **platform ownership and composition**, not canonical application routing. ## Motivation The original Workspace Shell, Context Contract, and Conversational Runtime work established the correct platform ownership model and delivered most of the shared facilities required by workspace applications. However, those architectural ideas and implementations are currently fragmented across: - the workspace contract; - shared `@xyence/shell` components; - Composer and conversation documentation; - Sales as the most complete consumer; - an older Orchestrator-local `PlatformShell`; - historical documentation that still describes conversation and Composer regions as placeholders. This allowed Orchestrator to consume part of the new shell architecture while leaving the conversation history and Composer regions unintegrated. The current Orchestrator application therefore presents an incomplete platform experience even though the shared capabilities already exist. More importantly, the same ambiguity could affect future workspace implementations. A developer or implementation agent following the repository today can discover the correct principles, but still has enough freedom to manually assemble or omit platform facilities. That is an architectural gap, not merely an Orchestrator UI bug. Before implementing additional workspace applications such as Web, Workspaces should expose an authoritative path that makes the intended ownership boundary unmistakable: **the platform owns the workspace experience; a workspace owns its domain.** ## Current state - `@xyence/shell` contains shared workspace UI and conversational infrastructure. - The platform Composer is already implemented. - Shared conversation history, persistence, runtime send/retry, attachments, screenshots, confirmations, receipts, and semantic-context plumbing already exist. - The workspace contract describes navigation, context types, capabilities, landing metadata, and related declarative workspace information. - Contract validity is already enforced by a shared CI harness. - Sales is currently the most complete consumer of the shared conversation surface. - Orchestrator uses an app-local `PlatformShell`. - The Orchestrator shell currently renders real navigation and domain content but placeholder conversation-history and Composer regions. - Orchestrator has a standalone Next topology with root-level routes, its own auth/scope composition, and existing control-plane/domain adapters. - Orchestrator is not currently mounted through the canonical Sales-style `WorkspaceContainer` routing topology. - Existing Workspaces documentation contains the correct ownership principles but is partly historical and inconsistent about the current full shell architecture. - `docs/adding-a-workspace-app.md` currently points developers toward Orchestrator as a reference host shape even though Orchestrator itself is missing the complete conversational integration. - The existing workspace contract harness validates workspace declarations but does not necessarily prove that a host consumed every mandatory platform-owned facility. ## Product principles - Conversation is a platform capability, not a workspace-specific chat feature. - Navigation chrome is a platform capability, not app-local UI. - The Composer is a platform capability, not an optional design pattern. - Shared mutation confirmation and receipt behavior is platform-owned. - Workspace applications should feel like different domains within one coherent product system. - Domain content remains first-class; the platform shell should support it rather than dominate it. - Workspace switching must switch conversation and platform scope without cross-workspace leakage. - In-workspace navigation refines semantic context without implicitly creating a conversation. - Users should not need to understand whether a workspace uses SPA routing, standalone Next routing, module routing, or another supported host topology. ## Architectural principles - Prefer one canonical Workspaces host-composition API over manual assembly of many independent platform components. - The composition API should own the standard platform facilities and expose narrow extension/adaptation points for host-specific concerns. - Workspace contracts provide declarative data, not shell-region JSX. - Platform shell facilities should live in shared Workspaces packages rather than being copied into individual apps. - Application-specific adapters are acceptable when topology differs, but those adapters connect into the platform architecture rather than replace it. - Shared APIs should not assume Sales routing unless that assumption is fundamental to the platform contract. - Existing authenticated/scoped `ApiClient` infrastructure should be reused for conversation/runtime/upload clients. - Backend authorization remains authoritative. - Browser-side code must not receive controller credentials, provider credentials, service JWTs, or equivalent secrets. - Active organization/workspace selection remains authoritative browser-side scope input. - Shared components should degrade visibly and safely when dependent platform APIs are unavailable. - Architectural exceptions should be deliberate and documented, not accidental consequences of local implementation.
Ready to release8/14/2026COMPLETEDInitiative Brief: Complete conversational shell integration in the Orchestrator workspace
# Initiative Brief: Complete conversational shell integration in the Orchestrator workspace ## Desired outcome Make the Orchestrator workspace consume the platform-owned conversational shell capabilities that already exist in `@xyence/shell`, so an authenticated Orchestrator user sees and can use the real conversation history and Composer alongside the Orchestrator domain UI instead of the current placeholder regions. The delivered experience should reuse the existing shared conversation, Composer, attachment, screenshot, persistence, runtime, confirmation, audit-receipt, and context infrastructure rather than creating an Orchestrator-specific chat implementation. This initiative is specifically about closing the Orchestrator integration gap. It must **not** be interpreted as an instruction to rewrite Orchestrator onto canonical Sales routing or otherwise reshape the application solely to match the Sales module topology. ## Motivation The “Workspace Shell, Context Contract, and Conversational Runtime” initiative successfully delivered the shared platform capabilities, but the Orchestrator workspace was only integrated with the first shell-layout stage. Its current app-local `PlatformShell` still contains the placeholder conversation and Composer regions introduced before the conversational runtime landed. As a result, production presents an internally inconsistent shell: - the global header and org/workspace switcher are present; - contract-driven navigation is present; - Orchestrator domain UI is present; - the platform conversational surface is absent even though its shared implementation has been delivered. This is an integration gap, not a missing feature implementation and not an environment/feature-flag problem. ## Current state - `apps/orchestrator` runs inside an app-local `PlatformShell`. - That shell renders contract-driven navigation and primary Orchestrator UI. - Its conversation-history and Composer regions remain static placeholders. - `@xyence/shell` already contains the platform Composer and conversation infrastructure. - Shared conversation capabilities include durable history, context events, attachments/screenshots, runtime send/retry, confirmation UX, and audit receipts. - `WorkspaceContainer` supplies workspace-scoped context management for canonical module-hosted workspaces. - Sales is currently the concrete workspace that mounts the shared conversation surface. - Orchestrator uses a different topology: a standalone Next application with root-level routes, its own `OrchestratorShell`, and its existing authenticated/scoped API client. - Orchestrator’s provider tree currently provides authentication, API client, telemetry, and org/workspace scope, but not the full conversation provider/runtime/upload wiring. - No current open Workspaces issue explicitly owns completion of the Orchestrator conversational-shell integration. ## Product principles - Conversation is a platform capability, not an Orchestrator-specific feature. - The conversational surface should be consistently available alongside focused domain UI. - Existing Orchestrator navigation and operational screens must remain first-class; conversation augments them rather than replacing them. - A user should not need to understand whether a workspace happens to be hosted through `WorkspaceContainer` or a standalone Next application. - Workspace switching must switch conversational scope without leaking history between workspace instances. - Navigation within the same workspace should refine conversational context rather than implicitly create a new conversation. ## Architectural principles - Reuse `@xyence/shell` conversation and Composer components; do not fork their behavior into `apps/orchestrator`. - Reuse `@xyence/api-client` conversation/runtime/upload clients and the existing authenticated/scoped Orchestrator API client wherever their contracts permit. - Preserve the Orchestrator application’s current backend authorization boundary. - Do not put control-plane credentials, service JWTs, provider credentials, or other secrets in the browser. - The active organization/workspace selected by the existing `OrgWorkspaceProvider` remains the authoritative browser-side scope input. - The implementation should identify the correct reusable shell composition boundary instead of blindly forcing the Orchestrator app through `WorkspaceContainer` if that would duplicate routing or authorization responsibilities. - Shell-owned regions remain platform-owned; Orchestrator contributes semantic context and domain UI, not custom conversational JSX or a parallel chat implementation. - **Do not interpret this initiative as “rewrite Orchestrator onto canonical Sales routing.”** Sales is a useful reference consumer of the shared shell, not the required application architecture for Orchestrator. Preserve Orchestrator’s existing route topology unless discovery proves a specific change is necessary to provide the shared conversational shell cleanly. ## Domain concepts - **Conversational shell surface**: the platform-owned conversation history, Composer, send state, confirmations, attachments, and receipts displayed alongside workspace domain UI. - **Workspace conversation scope**: the active `workspaceId` under which conversations are listed, created, resumed, and persisted. - **Semantic context**: the currently relevant Orchestrator domain object or view published into the conversation without changing workspace identity. - **Orchestrator shell adapter**: the minimum app-specific composition required to connect Orchestrator’s existing Next/auth/scope topology to the shared shell conversation capabilities. - **Primary domain surface**: the existing Orchestrator initiatives, workers, work items, planning, recovery, release-readiness, and related UI. ## Decisions - The shared `@xyence/shell` implementation is the canonical home of Composer and conversation UI. - Conversation persistence and runtime operations use platform backend APIs and authenticated browser session plumbing. - Conversation history is workspace-scoped. - Navigation does not implicitly create a conversation. - Mutating conversational capabilities require deterministic confirmation and durable receipts. - Attachments and screenshots remain user-initiated and retain contextual provenance. - Existing Orchestrator control-plane credentials remain server-side. - Existing Orchestrator domain screens and route structure should not be rewritten merely to obtain the Composer. - Sales’ canonical `/w/:workspaceId/*` module topology is not a prerequisite for Orchestrator conversational-shell integration. ## Rejected / deferred alternatives - Build a second Orchestrator-specific Composer or chat panel — rejected. This would immediately fork platform behavior. - Gate the existing Composer behind a new Orchestrator-only environment flag — rejected unless discovery proves a genuine deployment requirement. The missing surface is currently an integration gap, not a feature-toggle decision. - Rewrite Orchestrator onto canonical Sales routing or force it through the Sales-style module topology solely to obtain the Composer — rejected. Reuse the platform capabilities without unnecessary routing or application-topology churn. - Move the entire Orchestrator application to canonical `/w/:workspaceId/` routing as part of this initiative — deferred unless required by a demonstrated architectural constraint independently worth making. This initiative should close the conversational-shell gap without using it as a pretext for a routing migration. - Expose controller service credentials to the browser so conversation tools can call the controller directly — rejected. - Reimplement conversation persistence or runtime in the Orchestrator backend/controller — rejected; consume the existing platform facilities. - Add Orchestrator-specific conversational tools as part of this initiative — deferred. First make the platform conversation surface correctly available and operational. ## Constraints - Primary repository is `Xyence/workspaces`. - Supporting backend changes should occur only if discovery finds an actual missing API contract in `Xyence/outshine` or the Console gateway. - Existing Orchestrator authenticated domain reads/writes and service-side controller adapters must continue to work unchanged. - Existing org/workspace switcher behavior must remain functional. - Existing Orchestrator route topology should remain intact unless a narrowly justified change is required for the integration. - Cross-workspace conversation leakage is unacceptable. - The implementation must work under the canonical cookie/CSRF session boundary. - Existing shared conversation components and clients should be extended only where a genuinely reusable seam is missing. - Do not make production/deployment changes merely to compensate for missing application wiring. - Responsive behavior and accessibility of the shared Composer/timeline must be preserved. ## Invariants - Backend authorization remains authoritative. - Active workspace scope accompanies every relevant conversation request. - Conversation history from workspace A is never shown after switching to workspace B. - A route change inside the same selected workspace does not automatically create a new conversation. - The Composer never holds platform/provider/control-plane secrets. - Mutating conversational actions cannot bypass the existing deterministic confirmation contract. - Orchestrator-owned primary UI never injects arbitrary JSX into shell-owned conversation regions. - Existing Orchestrator operational behavior remains usable if the conversation backend is unavailable; conversational failure should degrade visibly rather than blank or break the domain workspace. - The shared shell remains the canonical implementation of Composer/timeline behavior. - Orchestrator does not need to adopt Sales routing semantics in order to satisfy this initiative. ## Repository scope - `Xyence/workspaces` — primary implementation: Orchestrator shell/provider integration, semantic-context publication, styling/layout reuse, tests, and removal of obsolete placeholder regions. - `Xyence/outshine` — only if a discovered conversation API/runtime capability is actually missing for an Orchestrator workspace scope. - `Xyence/console` — only if the existing Workspaces BFF proxy does not currently forward a required conversation/runtime/upload route. - `Xyence/orchestrator` — no feature implementation expected unless discovery identifies a missing authoritative Orchestrator capability that the shared runtime must call; ordinary Composer integration belongs in Workspaces. ## Expected behavior - An authenticated user entering the Orchestrator workspace sees the real platform conversation history and Composer rather than placeholder copy. - The conversation surface uses the currently selected organization/workspace from the existing Orchestrator switcher. - Switching workspaces loads that workspace’s conversation history or its appropriate empty/start state and never retains the prior workspace’s messages. - The user can create or resume a conversation, type and send a message, and see the persisted user and assistant turns after reload. - Runtime send failures produce the existing safe error/retry experience rather than breaking the Orchestrator domain UI. - The user can attach files and initiate screenshots through the existing shared Composer behavior where browser support permits. - Attachment and screenshot messages retain the active Orchestrator page/domain context supported by the shared context contract. - The Orchestrator workspace publishes useful semantic context for at least the principal object-detail routes where stable identifiers already exist, such as initiative and work-item detail, without inventing new authorization semantics. - Navigating between Orchestrator views updates/refines semantic context while retaining the active conversation. - Mutating actions requested through conversation retain the shared explicit-confirmation and audit-receipt UX. - Existing Orchestrator navigation, initiative/work-item/worker screens, workspace switcher, user menu, route telemetry, and permission-denied behavior continue to work. - Existing Orchestrator URLs continue to work; this initiative does not require users to move to Sales-style `/w/:workspaceId/*` routes. - At desktop widths the domain UI and conversational surface are simultaneously usable; at narrow widths the shared responsive behavior remains usable without inaccessible controls or clipped content. - No “Composer coming soon” or “Conversation history will appear here” placeholder remains in the production Orchestrator shell. ## Open questions - What is the cleanest reusable composition for standalone workspace apps like Orchestrator: enhance the shared platform shell to own `ConnectedConversationPanel`, introduce a reusable shell-conversation adapter/provider, or compose the existing primitives directly in `OrchestratorShell`? - Which shared provider/client construction currently exists only implicitly in the Sales/canonical-container path and should be extracted so standalone apps can consume it without duplication? - Does the Console `/api/workspaces/*` proxy already forward all conversation, runtime, confirmation, and upload paths required by the Orchestrator app? - Which Orchestrator routes have stable domain identities worth publishing as semantic context in this pass? - Should conversation UI appear for actors who can enter the workspace but lack some Orchestrator-specific capability, with the backend independently authorizing conversation tools as today? - What graceful state should be shown if conversation APIs are unavailable while the Orchestrator control-plane UI itself remains healthy? - Can the integration be completed while preserving the existing Orchestrator root-level Next route topology? This should be the default assumption; a routing migration requires separate architectural justification and must not be inferred from Sales being the current reference implementation.
Ready to release8/13/2026COMPLETEDInitiative Brief: Complete the OutShine Notification Runtime and External Event Ingestion
# Initiative Brief: Complete the OutShine Notification Runtime and External Event Ingestion ## Desired outcome Complete the existing OutShine notification subsystem so that notification-worthy events reliably flow from creation through routing and delivery, and expose a safe service-to-service ingestion contract that other Xyence services can use. This initiative should **finish and harden the notification architecture already present in OutShine rather than replace it**. The immediate cross-service consumer is `Xyence/orchestrator#355`, which needs to raise operator-facing notifications for events such as provider usage limits, unrecoverable work-item failures, human-required merge conflicts, and stalled runs. ## Current state - OutShine already contains a substantial notification foundation: - durable `NotificationEvent` records; - declarative notification routes; - delivery records and retries; - correlation-key deduplication; - payload redaction; - message templates; - email-provider abstraction; - rate-limiting seams; - administrative APIs for inspecting events, routes, deliveries, and templates; - Console UI for operational notification management; - notification emission from existing domains such as Work Items. The architecture is directionally correct: **event → route resolution → delivery → provider** OutShine should remain the canonical owner of this pipeline. However, the subsystem is incomplete in several important ways. Event creation does not itself complete notification delivery — `create_notification_event()` persists a durable event, but routing and delivery happen separately through `process_notification_event()`. Several internal callers appear to emit events without clearly ensuring they are subsequently processed. An external ingestion endpoint that merely calls `create_notification_event()` would therefore accept an event successfully while potentially leaving it indefinitely in `pending`. There is no service-to-service notification ingestion API — Current notification APIs are primarily administrative/read/operational APIs. External services cannot safely raise a platform notification through OutShine. This is the direct blocker for `Xyence/orchestrator#355`. Notification preferences appear only partially implemented — The schema and documentation describe per-user notification preferences, but the current routing path does not appear to consistently enforce them. The initiative should reconcile the implementation with the intended contract rather than leaving a feature that exists in schema and documentation but not reliably in behavior. Multi-channel support is mostly a future seam — The data model anticipates channels beyond email, but email is currently the only meaningful outbound provider. Unsupported channels are intentionally suppressed. This initiative should preserve that extensibility without expanding scope into implementing SMS, chat, push, or other channels. ## Rejected / deferred alternatives - replacing the notification architecture; - implementing a notification subsystem inside Orchestrator; - SMS delivery; - chat delivery; - mobile push; - browser push; - generalized webhook delivery unless already present and trivially supported; - introducing Kafka, SQS, Redis queues, Celery, or another worker architecture solely for notifications; - building a full consumer-facing notification inbox; - broad UI redesign of the Console Notifications area; - notification of every routine platform event; - workflow authoring redesign. ## Repository scope - In Scope - canonical raise-and-process notification service operation; - service-authenticated external event ingestion; - mandatory/strong correlation-key deduplication for service producers; - redaction and payload validation; - synchronous route/delivery processing; - existing producer audit and migration; - Work Item notification-path verification/fix; - notification preference completion or explicit reconciliation; - route/target contract reconciliation; - operational logging and tests; - documentation of the external producer contract; - support necessary for `Xyence/orchestrator#355`. ## Expected behavior - [ ] OutShine has one canonical service operation for raising a notification-worthy event through persistence, routing, and supported delivery. - [ ] Existing code can still create a durable event without processing only where that lower-level behavior is explicitly required. - [ ] `POST /api/notifications/events` or the equivalent service API accepts authenticated events from trusted Xyence services. - [ ] Service-ingested events require or strongly enforce deterministic correlation-key deduplication. - [ ] The ingestion path validates payload size/shape and redacts prohibited sensitive data before persistence. - [ ] Successfully ingested events are processed through routing and delivery rather than being left indefinitely `pending`. - [ ] Email remains the supported outbound channel; unsupported channels remain explicit, observable suppressed seams. - [ ] Notification provider failure preserves the durable event and delivery failure state. - [ ] Producer operations remain unaffected by notification failure. - [ ] Existing OutShine notification-event producers are inventoried. - [ ] Existing callers that intend actual notification delivery use the canonical processed path. - [ ] Work Item notifications are verified to reach the routing/delivery pipeline. - [ ] `NotificationPreference` behavior is either fully enforced according to a documented contract or explicitly removed from claims of current runtime behavior. - [ ] Route target types are consistent across schema, models, service validation/resolution, APIs, and documentation. - [ ] Console operators can inspect accepted events, routing outcomes, suppressed deliveries, failed deliveries, and retries. - [ ] Tests cover event creation, processing, dedupe, redaction, route resolution, preference behavior, provider failure, retry, service authentication, malformed payloads, abuse/flood protection, and fail-open producer behavior. - [ ] Documentation defines the service producer contract and includes a safe example payload. - [ ] The resulting API satisfies the OutShine dependency in `Xyence/orchestrator#355`.
Ready to release8/12/2026COMPLETEDInitiative Brief: First-Class Release Planning and Cutting in Orchestrator
# Initiative Brief: First-Class Release Planning and Cutting in Orchestrator ## Desired outcome Create a release-management capability that allows an operator to: * Identify completed work that has not yet been released. * Group one or more completed initiatives into a logical release. * Determine which repositories participate in that release. * Review initiative and repository readiness before release. * Capture the exact repository state that will be released. * Assign or propose release versions/tags. * Generate editable release notes. * Explicitly cut/publish the required GitHub Releases. * Observe the outcome of the release operation. * Retry or recover from partial failures safely. * Preserve a durable record of what was included in each release. The feature should integrate naturally with Orchestrator's initiative lifecycle without making releases mandatory during initial initiative planning. ## Rejected / deferred alternatives - The initial implementation does not need to provide: - A general-purpose CI/CD platform - Full environment promotion pipelines - Release trains - Scheduled release windows - Automated production rollback orchestration - Package-registry management - Automatic semantic-version calculation from conventional commits - Public changelog publishing - Customer communication workflows - Organization-wide change-management governance - Strict transactional release across multiple repositories These may be considered future roadmap items if experience demonstrates a need. ## Expected behavior - The initiative is complete when: - Orchestrator has a first-class Release domain model. - Releases can contain multiple initiatives. - Releases can span multiple repositories. - Repository-specific versions/tags and release status are represented. - Completed/unreleased initiatives can be identified for release planning. - Initiative assessment state contributes to release readiness. - Reasonably complete initiatives with deferred roadmap work can remain releasable. - Release preparation captures immutable repository SHAs/refs. - Release notes can be generated and edited. - The UI provides release list, release detail, readiness, and explicit release actions. - Orchestrator can create/publish GitHub Releases against the intended repository refs. - Existing GitHub Release-triggered deployment workflows remain the downstream deployment mechanism. - Multi-repository partial failures are persisted accurately. - Failed release operations can be safely retried without duplicating successful releases. - Released records preserve an auditable snapshot of initiatives, repository refs, versions, actors, and timestamps. - Appropriate automated tests cover release lifecycle, readiness, snapshotting, GitHub integration, idempotency, and partial-failure recovery. - Existing initiative planning/execution behavior continues to function without requiring every initiative to be assigned to a release.
Ready to release8/11/2026COMPLETEDInitiative Brief: Deferred Work and Roadmap Lifecycle
# Initiative Brief: Deferred Work and Roadmap Lifecycle ## Motivation Large initiatives often reveal additional work that should not be completed within the current initiative. Common reasons include: * The work is outside the initiative brief. * The current effort intentionally establishes only a scaffold or foundation. * Further implementation should wait until the scaffold has been exercised. * Product or architectural direction is required before proceeding. * The work is valid but would create inappropriate scope expansion. Orchestrator can currently identify and defer such work, including a rationale and checkpoint for revisiting it. However, deferred planning items remain unresolved and can prevent an initiative from reaching `COMPLETED` even after assessment has determined that all brief criteria were delivered. The current escape mechanisms do not accurately represent the situation: * Force-closing effectively records valid future work as waived. * Retracting implies that the item should no longer be considered valid. * Leaving planning open causes an otherwise delivered initiative to remain indefinitely in an executing state. At the same time, simply discarding the information loses valuable knowledge about future capabilities, partial scaffolding, architectural intent, and the conditions under which further work should be reconsidered. Orchestrator needs a durable lifecycle for this information. --- ## Constraints - Do not redesign the entire Orchestrator planning model unless required to support this lifecycle. - Do not introduce a separate unrelated project-management system. - Reuse existing initiative, planner, assessment, repository, workspace, and persistence abstractions where sensible. - Preserve existing force-close, retract, or waiver functionality where it remains semantically useful. - Do not make all roadmap items mandatory scope for future initiatives. - Do not require completion of deferred roadmap work before an originating initiative can complete. - Do not duplicate a single cross-repository roadmap concern into multiple repository records solely because multiple repos are affected. - Avoid destructive migration of existing planning or initiative history. - Prefer backward-compatible evolution of existing state where practical. --- ## Expected behavior - Establish a Durable Roadmap Model — Orchestrator must support a durable representation of anticipated future work. The initial storage implementation may be Markdown-backed if that is the most appropriate fit with the existing repository/planning architecture, but roadmap items must be represented with enough structure that Orchestrator can reliably identify, reconcile, and update individual entries. Each roadmap item should have a stable identity. At minimum, preserve: - stable roadmap item ID - title - current status - description or intended capability - reason it was deferred or recorded - origin/provenance - relevant repository, workspace, or platform scope - checkpoint or conditions under which the work should be revisited - any known existing scaffold or partial implementation - related capabilities/components where known - creation/update history sufficient for reconciliation - relationship to a later initiative if promoted into implementation Do not reduce roadmap entries to unstructured TODO bullets. --- - Support Multiple Roadmap Scopes — Do not assume that every roadmap item belongs exclusively to one repository. Orchestrator initiatives frequently span multiple repositories and platform concerns. The roadmap model must allow an item to be associated with an appropriate ownership scope, such as: ```text repository workspace platform ``` Equivalent terminology is acceptable if another abstraction already exists in Orchestrator. A repository-specific capability may live with that repository. A cross-repository workspace or platform capability should not need to be duplicated into several repo roadmaps merely to satisfy repository ownership. The planner should determine the most appropriate available scope based on the architecture and affected components. --- - Make `DEFERRED` a Valid Planning Disposition — A valid deferred item must no longer block initiative completion once it has been durably captured. The semantics should distinguish at least: Deferred — The work is considered legitimate future work but is intentionally outside the current initiative. It remains active in roadmap state. Waived — The work has consciously been determined not to be required or pursued. Waiving should not be used merely because an item is outside the current initiative. Retracted / Withdrawn — The deferred/planned item itself is no longer considered valid, was created incorrectly, or should otherwise cease to exist as anticipated work. Exact status names may align with existing Orchestrator terminology, but these meanings must remain distinct. --- - Add a "Defer and File" Lifecycle — Provide a normal completion path whereby an initiative's deferred item can be: - classified as legitimate follow-on work; - associated with the appropriate roadmap scope; - created or reconciled against an existing roadmap item; - recorded with its rationale and checkpoint; - marked durably captured for the originating initiative; and - treated as resolved for purposes of closing current planning. Once all non-delivered planning items have valid terminal dispositions for the current initiative, planning must be closable. An initiative that has received a delivered assessment should therefore be capable of reaching `COMPLETED` while roadmap items originating from it remain active future work. This should not require a force-close. --- - Preserve Initiative Provenance — Do not remove or overwrite deferred-work evidence from the initiative after it has been filed into the roadmap. The system should support both questions: - What future work is currently anticipated? - What work did this particular initiative discover and defer? The initiative should retain enough information to identify: - the original deferred item; - its rationale; - its checkpoint; - the roadmap item to which it was filed or reconciled; and - its final disposition within the initiative. The roadmap should reciprocally record the originating initiative where applicable. --- - Consult Roadmap State During Planning — Relevant roadmap state must become an input to planning new initiatives. The planner should inspect roadmap items whose scope or capability appears relevant to the initiative being planned. The roadmap is not merely archival. However, roadmap consultation must not cause automatic scope expansion. The planner should reason about each relevant item and determine whether it is: - incorporated into the new initiative; - partially incorporated; - still deferred; - adjacent but outside scope; - superseded by the initiative's proposed architecture; - already satisfied by existing implementation; or - unrelated after closer inspection. A roadmap item's existence alone must not make it a requirement of a new initiative. --- - Record Roadmap Reconciliation During Planning — Planning should provide evidence that relevant known roadmap items were considered. A planning artifact or equivalent structured state should be able to express reconciliation such as: ```text RM-014 — Deeper suggestedActivities semantics Relevant: yes Disposition: incorporated Reason: this initiative now defines activity-driven Composer behavior RM-021 — Confirmation policy management UI Relevant: adjacent Disposition: remains deferred Reason: administrative policy surfaces remain outside this initiative ``` Exact presentation is implementation-dependent. The key requirement is that roadmap consideration and disposition must be inspectable rather than occurring as invisible planner behavior. --- - Prevent Duplicate Roadmap Items — Roadmap filing and future planning must reconcile against existing roadmap state before creating new entries. If Orchestrator rediscovers substantially the same future capability, it should prefer updating or linking to the existing item rather than creating another independent entry. Stable IDs should make exact relationships explicit once established. Semantic matching may be used to identify likely duplicates where no explicit relationship exists, but Orchestrator should preserve distinctions when similar-looking items represent genuinely separate concerns. --- - Support Promotion Into Future Initiatives — When a future initiative intentionally takes on a roadmap item, establish a durable relationship between them. For example: ```text roadmap item: status: planned promoted_to: <initiative-id> ``` Equivalent representation is acceptable. The new initiative should know that the capability originated as known roadmap work. Promotion should not erase the roadmap record. --- - Reconcile Roadmap State During and After Delivery — Roadmap maintenance must not stop when an item is incorporated into an initiative. When implementation or assessment establishes that roadmap work has been completed, superseded, or otherwise resolved, update its roadmap status accordingly. Useful states may include concepts such as: - candidate / deferred - planned - in progress - delivered - superseded - withdrawn / no longer relevant Do not introduce unnecessary workflow complexity merely to support a large status vocabulary. Use the smallest state model that accurately represents the lifecycle. What matters is that stale roadmap entries do not remain indefinitely presented as anticipated future work after reality has changed. --- - Preserve Revisit Checkpoints — The checkpoint or trigger for reconsidering deferred work is important planning information and should be treated as first-class data. Examples: - evidence of stable usage of the current scaffold; - an operator decision; - product direction on interaction semantics; - completion of a prerequisite capability; - observed demand or usage behavior. Prefer a concrete `revisit_when`, `checkpoint`, or equivalent field over generic language such as "do later." The planner should retain checkpoints when filing deferred items and consider them when evaluating roadmap relevance in future initiatives. --- - Preserve Existing Scaffold Information — Where follow-on work has already been partially scaffolded, stubbed, contracted, or otherwise represented in the current implementation, record that information with the roadmap item when reasonably available. For example: ```text Existing scaffold: - suggestedActivities exists in the workspace contract. - Current implementation supports basic landing behavior. - Parameterized activity semantics are not defined. ``` This information should help future planning avoid rediscovering implementation history through repository archaeology. Do not require exhaustive code analysis merely to file a roadmap item. --- - Keep the Roadmap Focused — The roadmap should represent meaningful anticipated product, capability, architecture, or implementation work. It should not become a general dumping ground for: - trivial cleanup; - minor cosmetic defects; - incidental TODOs; - temporary debugging notes; - implementation details already adequately represented by current initiative tasks. The planner should use reasonable judgment about whether an item represents meaningful future work worthy of durable roadmap memory. Existing issue/defect/task mechanisms should continue to handle concerns better suited to those systems. ---
Ready to release8/11/2026COMPLETEDInitiative Brief: Workspace Shell, Context Contract, and Conversational Runtime
# Initiative Brief: Workspace Shell, Context Contract, and Conversational Runtime ## Desired outcome Establish the primary interaction model for Xyence Workspaces: a consistent platform-owned shell with a persistent, context-aware conversational interface that every workspace can participate in through explicit contracts. Workspaces should become more than a launcher for independent applications. It should provide the common human interface through which users select what kind of work they want to perform, see domain-specific information, converse naturally about that work, attach visual or file-based evidence, and invoke authorized domain capabilities without each workspace rebuilding its own navigation, conversation system, attachment handling, or AI integration. The platform shell should own: * the global header; * workspace selection; * organization/account context; * the hybrid navigation rail; * durable conversations and conversation history; * Composer; * file/image attachments; * direct screenshot capture; * context-change events; * responsive/mobile behavior; * shared confirmation/audit conventions for AI-initiated actions. Individual workspaces should own their primary domain UI while declaratively contributing navigation, context, capabilities, actions, and landing-page information to the shell. The Orchestrator workspace will be the first substantial consumer of this architecture, but this initiative must establish reusable platform contracts rather than embedding Orchestrator-specific assumptions. ## Motivation The current workspace-based applications already share portions of a common shell, including global workspace and organization selection, but the interaction model is not yet formalized strongly enough to support the platform's longer-term direction. The intended user experience is increasingly conversational. A user should be able to enter Workspaces and answer a simple question: **What do you want to work on?** Examples might include: * Software development * Websites * Sales * Marketing Selecting a workspace changes both the primary application UI and the context of the shared Composer. Within a workspace, selecting a particular object—such as a website, repository, initiative, lead, or campaign—should further refine the context available to the conversation without forcing the user into a new conversation. Without a shared platform architecture, each workspace is likely to independently implement: * navigation; * AI/chat UI; * conversation persistence; * context handling; * attachment uploads; * screenshot support; * action confirmation; * responsive behavior. That would recreate the fragmentation Workspaces is intended to eliminate. A platform-level contract is therefore needed before conversational features are added deeply to individual workspace applications. ## Product principles - Workspaces owns the shell — Workspace applications participate in the shell. They do not replace it. Conversation is a platform capability — Orchestrator, Web, Sales, Marketing, and future workspaces should not implement independent chat systems. Workspace selection establishes conversational scope — Entering a workspace determines: - the relevant conversation history; - the default domain; - available domain capabilities; - visible workspace navigation; - initial landing content. Navigation may refine conversation context without starting a new conversation — Selecting an object within a workspace should normally update the existing conversation context. A new conversation is an explicit user action, not a side effect of navigation. Context changes are visible — A conversation must never silently change semantic scope. When relevant context changes, the conversation should record a durable context event such as: > Context changed · stlouishighrises.com or: > Context changed · Xyence/workspaces repository Primary UI and conversation complement one another — Composer must not become a blank prompt that carries the full burden of teaching users what the product can do. Every workspace should provide meaningful structured landing content and suggested activities. The shell is declarative — Critical shell regions should consume workspace-defined metadata/contracts rather than arbitrary workspace-provided React UI. This preserves consistency, accessibility, security, mobile behavior, and future evolution. ## Rejected / deferred alternatives - Full Orchestrator ideation implementation. - Full Web workspace implementation. - Full voice mode. - General-purpose unrestricted consumer chat. - Cross-workspace conversation handoff in the first release. - Autonomous browser screenshotting by the AI. - Allowing workspaces arbitrary DOM/React control over platform shell regions. - Moving domain ownership into Workspaces. - Replacing domain service APIs with MCP solely for internal integration. ## Invariants - The platform owns the shell. - The platform owns conversation persistence and Composer. - Workspaces contribute shell behavior through declared contracts. - Primary domain UI remains workspace-owned. - Navigation does not silently create conversations. - Material context changes are visible and durable. - Historical messages retain the context under which they were sent. - User-provided context cannot bypass authorization. - Provider and service credentials remain server-side. - Conversation does not implicitly authorize mutating actions. - Screenshot and attachment access follows conversation authorization. - Critical shell regions are not arbitrary workspace-rendered JSX. - Domain systems remain authoritative for domain data and actions. ## Repository scope - `Xyence/workspaces` — Primary implementation. Likely includes: - shell architecture; - workspace contract; - navigation contract; - context contract; - capability/action contracts; - conversation persistence; - Composer; - attachment and screenshot UX; - conversation runtime integration; - landing page; - responsive behavior; - contract validation. `Xyence/outshine` — Only where platform authentication, organization/workspace identity, storage, or authorization boundaries require extension. Avoid making Outshine the owner of conversation semantics solely because it already provides platform APIs. `Xyence/orchestrator` — No substantial Orchestrator-domain implementation is required by this foundation initiative except where needed to keep the existing workspace functioning during shell migration. Full Orchestrator conversational integration belongs to the follow-on initiative. ## Expected behavior - A user can land in Workspaces and select a workspace from a meaningful task/domain-oriented landing experience. - The existing organization/workspace header behavior is retained or cleanly migrated. - The platform renders a consistent shell around at least one workspace. - A workspace can declaratively contribute navigation. - A workspace can publish active semantic context to the shell. - Composer is platform-owned and consistently available. - Durable conversations can be created, resumed, and archived. - Conversation history defaults to the active workspace. - Changing selected domain context does not automatically create a new conversation. - Material context changes appear in conversation history. - Composer supports image/file attachments. - Composer provides low-friction screenshot capture. - Screenshot messages retain useful current-page/workspace context. - The server-side conversation runtime can consume workspace-declared read capabilities. - Mutating capabilities may require deterministic confirmation outside model judgment. - All context and capability access is re-authorized server-side. - Long conversations use bounded context rather than unlimited transcript replay. - Conversation/action provenance is durably recorded. - The shell works at desktop and mobile viewport sizes. - The architecture is ready for later voice input without replacing the message model. - Workspace contracts are versionable and testable. - Conversational model/tool failures are observable without unsafe logging.
Ready to release8/10/2026COMPLETEDInitiative Brief: Workspace & Managed-Context Authorization True-Up
# Initiative Brief: Workspace & Managed-Context Authorization True-Up ## Desired outcome Bring Xyence Workspace authorization, Doorway authorization, and Console access-management UI into alignment with the authorization architecture that already exists in Outshine. The primary goal is to make Workspace access fully manageable through first-class UI surfaces while clarifying the architectural distinction between **Workspaces**, **Doorways**, and other authorization scopes. This initiative should **not introduce a new identity system, permission engine, membership store, or authentication architecture**. Outshine remains the canonical source of truth for users, principals, roles, permission grants, and authorization decisions. The implementation should build on the existing `PermissionGrant`, `PermissionRole`, `Principal`, `WorkspaceInstance`, Workspace membership APIs, and `permission_engine.can(...)` machinery. --- ## Rejected / deferred alternatives - Do NOT: - replace the Outshine permission engine, - create a second Workspace permission system, - create a new identity database, - migrate authentication out of Outshine, - build Account Center now, - rewrite `auth.xyence.io`, - turn Workspaces into Doorways, - remove Doorways, - encode Workspace access using Console-local teams, - duplicate permission state in Console, - hard-code the system around Sales, - make `workspace_admin` global, - redesign all authorization scopes in one pass, - undertake unrelated Console navigation or styling refactors. ---
Ready to release8/9/2026COMPLETED