Feat v0.3.4 team roles + multi-party validation (#18)
Custom team roles: removed CHECK constraint on team_members.role, roles stored in teams.settings, roles API, stage_config.required_role enforced on claim. Multi-party signoff: workflow_signoffs table, validation gate in advanceInternal, SubmitSignoff engine method, signoff HTTP API. Frontend: dynamic role management, stage config validation UI, signoff panel. Design docs for extension lifecycle and trigger composition. 20 store tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
49
docs/DESIGN-EXTENSION-LIFECYCLE.md
Normal file
49
docs/DESIGN-EXTENSION-LIFECYCLE.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Extension Lifecycle: Permanent vs PoC
|
||||
|
||||
## Overview
|
||||
|
||||
Packages (extensions) fall into two categories: **permanent** and **PoC** (proof-of-concept).
|
||||
This classification drives install-by-default behavior and maintenance expectations.
|
||||
|
||||
## Permanent Packages
|
||||
|
||||
Permanent packages are part of the platform kernel or essential surfaces. They are always
|
||||
available and maintained by core contributors.
|
||||
|
||||
| Package | Reason |
|
||||
|------------------|--------------------------------|
|
||||
| admin | System administration surface |
|
||||
| team-admin | Team management surface |
|
||||
| settings | User settings surface |
|
||||
| login | Authentication surface |
|
||||
| welcome | Onboarding / empty-state |
|
||||
|
||||
## PoC Packages
|
||||
|
||||
Everything else in `packages/` is PoC. These demonstrate the extension model but are not
|
||||
required for platform operation. Examples: tasks, schedules, dashboard, editor, git-board,
|
||||
icd-test-runner, sdk-test-runner.
|
||||
|
||||
Retired builtins (csv-table, diff-viewer, js-sandbox, katex-renderer, mermaid-renderer,
|
||||
regex-tester) are PoC packages migrated from the kernel during the v0.2.9 retirement.
|
||||
|
||||
## Graduation Criteria
|
||||
|
||||
A PoC package may be promoted to permanent when all of the following are met:
|
||||
|
||||
1. **Active usage** — 3+ active users or teams depend on it.
|
||||
2. **Test coverage** — At least basic smoke tests exist (Starlark or integration).
|
||||
3. **No kernel special-casing** — The package operates entirely through the public extension
|
||||
API. No `if pkg == "X"` branches in core.
|
||||
4. **Documentation** — README with install instructions, config options, and screenshots.
|
||||
5. **Maintenance owner** — A named contributor commits to reviewing issues.
|
||||
|
||||
## Deprecation
|
||||
|
||||
Packages that no longer meet graduation criteria (e.g., zero usage for 6 months) may be
|
||||
archived. Archived packages remain installable but receive no updates.
|
||||
|
||||
## Install Model
|
||||
|
||||
All packages use explicit installation: `POST /api/v1/packages/:id/install`. There is no
|
||||
auto-install. The kernel ships clean; teams choose what they need.
|
||||
57
docs/DESIGN-TRIGGER-COMPOSITION.md
Normal file
57
docs/DESIGN-TRIGGER-COMPOSITION.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Trigger Composition: Triggers, Schedules, and Workflows
|
||||
|
||||
## Overview
|
||||
|
||||
Three automation primitives exist in the platform: **triggers** (event-driven), **schedules**
|
||||
(time-driven), and **workflows** (multi-step state machines). This document defines how they
|
||||
compose without creating circular dependencies.
|
||||
|
||||
## Composition Rules
|
||||
|
||||
### Triggers can start workflows
|
||||
|
||||
A trigger's Starlark handler may call `workflow.start(workflow_id, data)` to create a new
|
||||
workflow instance. This is the primary entry point for event-driven workflow initiation.
|
||||
|
||||
Example: a `ticket.created` trigger fires and starts an approval workflow.
|
||||
|
||||
### Schedules can start workflows
|
||||
|
||||
A schedule's Starlark handler may also call `workflow.start(...)`. This enables time-based
|
||||
batch processing workflows.
|
||||
|
||||
Example: a daily 9am schedule starts a standup collection workflow.
|
||||
|
||||
### Workflows emit events that triggers listen to
|
||||
|
||||
Workflow lifecycle events (`workflow.started`, `workflow.advanced`, `workflow.completed`,
|
||||
`workflow.signoff`, etc.) are published on the event bus. Triggers may subscribe to these
|
||||
events to perform side effects (notifications, external API calls, audit logging).
|
||||
|
||||
### Workflows cannot start triggers or schedules
|
||||
|
||||
Workflows do not directly invoke triggers or create schedules. Workflow Starlark hooks
|
||||
operate within the workflow's own context and do not have access to trigger/schedule
|
||||
management APIs. This prevents uncontrolled fan-out.
|
||||
|
||||
## Circular Invocation Guard
|
||||
|
||||
The automated stage cycle guard (max 10 consecutive automated stages) already prevents
|
||||
infinite loops within a single workflow. Cross-workflow cycles are prevented by this rule:
|
||||
|
||||
**A workflow event handler (trigger) may start a new workflow instance, but the new instance
|
||||
is not processed synchronously.** It enters the work queue as a separate execution context.
|
||||
The bus does not re-enter the originating workflow's advance call.
|
||||
|
||||
This means:
|
||||
- `workflow.completed` trigger → `workflow.start(B)` is allowed (async).
|
||||
- Workflow A automated stage → `workflow.start(B)` where B immediately completes and
|
||||
triggers A again → allowed but rate-limited by the cycle guard on each individual workflow.
|
||||
|
||||
## Not Supported (by design)
|
||||
|
||||
- Triggers cannot modify a running workflow instance (read-only access via Starlark builtins).
|
||||
- Schedules cannot advance or cancel workflow instances directly.
|
||||
- Workflows cannot create, modify, or delete triggers or schedules.
|
||||
|
||||
These restrictions keep the composition model simple and auditable.
|
||||
Reference in New Issue
Block a user