docs(#751): publish native Kanban SOT canon
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
Hermes Agent
2026-07-14 12:00:52 -05:00
parent d077183554
commit 728d205b3e
18 changed files with 4077 additions and 11 deletions

View File

@@ -0,0 +1,59 @@
VERDICT: GO
# Native Kanban/SOT canon independent re-review 2
Independent read-only re-review of the complete updated staged canon. Prior proposal-audit blocker is closed; no KCR-001016 regression or new blocker found.
## Prior blocker closure
- `contracts/kanban-schema.v1.ts:836-837` declares the required unique `task_events(workspace_id,id)` key before proposal declaration.
- `contracts/kanban-schema.v1.ts:885-894` adds both composite proposal audit FKs—submission and accepted-command event—to that exact workspace-aware key with `RESTRICT`.
- Declaration/migration order is executable and explicit in `SHARED-CONTRACT.md:79-91`: events/key first, proposal table second, both FKs third/fourth, then command enablement. This avoids forward-reference/circular-DDL ambiguity.
- Submission/acceptance semantics are frozen in `SHARED-CONTRACT.md:87-91`: preallocate proposal ID; create exact `change_proposal.submitted` event and proposal in one transaction; on acceptance lock proposal/target, execute the normal command, and bind only a same-workspace/target event with submission causation and `payload.changeProposalId` equal to the locked proposal.
- Required missing, foreign-workspace, unrelated-proposal, unrelated-target, and unrelated-command negatives are explicit in `REQUIREMENTS.md` REQ-SOT-004 and `SHARED-CONTRACT.md:121`; KBN-100/110/140 own migration, service, and integration evidence.
## KCR closure matrix
| KCR | Status |
| ------------------------------------------------------ | ------ |
| 001 health/proof | CLOSED |
| 002 error discrimination | CLOSED |
| 003 approval/assignment binding | CLOSED |
| 004 monotonic fencing/composites | CLOSED |
| 005 tenant-safe relations | CLOSED |
| 006 outage proposal persistence/commands/audit binding | CLOSED |
| 007 dependency/API freeze sequencing | CLOSED |
| 008 concrete N-1 map | CLOSED |
| 009 dependency uniqueness | CLOSED |
| 010 project congruence | CLOSED |
| 011 immutable audit retention | CLOSED |
| 012 retry/quarantine/vocabulary | CLOSED |
| 013 archive/tags target semantics | CLOSED |
| 014 recovery validator/owner slice | CLOSED |
| 015 pure Coordinator split | CLOSED |
| 016 health code/state pairing | CLOSED |
Fixed invariants remain consistent: PostgreSQL is sole writable SOT; writes require transaction-local proof and fail closed; exports never import sources; notes are attributable proposals only; Coordinator has no scope/gate/certify/merge authority; Certifier has no merge authority.
## Reproducible validation evidence
Executed read-only with current-stack config/toolchain `/src/mosaic-mono-v1`:
```text
./node_modules/.bin/prettier --config /src/mosaic-mono-v1/.prettierrc --check <all 9 publication artifacts>
PASS: All matched files use Prettier code style.
strict TypeScript --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext <four contract copies with current Drizzle node_modules resolution>
PASS
cascade/TODO/TBD/stale-hold grep plus composite-FK/semantic-marker invariant checks
PASS
```
The TypeScript check used a disposable copy under `/home/hermes/agent-work` solely to provide external-file NodeNext dependency resolution; the reviewed staging artifacts were not modified.
## Residual findings
None blocking. Implementation must execute the frozen KBN-100/KBN-110/KBN-140 proposal-event-chain tests and SecReview evidence before feature release, as already required by the canon.
No artifact source repository, branch, PR, or provider state was modified.

View File

@@ -0,0 +1,357 @@
# Independent Review — Native Kanban/SOT Canon
**Reviewer:** `enhance-sol` (independent of author `planner-sol`)
**Date:** 2026-07-13
**Review mode:** design/contract only; read-only against the staged canon
**Source plan:** `/home/hermes/agent-work/planning/mosaic-native-kanban-sot-plan.md` (`sha256:96ea4fb91436ec9a53f371d27276e27f62ecf817662599ff9152df0db55296e5`)
**Canon reviewed:** every listed artifact under `/home/hermes/agent-work/planning/kanban-canon/`, including the four TypeScript contracts; the author scratchpad was also read as validation context.
## Executive verdict
# NO-GO
The canon is not freeze-ready. I found **8 BLOCKERs**, **7 MAJORs**, and **1 MINOR**. The prose preserves the ratified authority model well, but the frozen types/schema leave concrete fail-closed, approval, fencing, tenant, outage-proposal, migration, and parallelization gaps. Those gaps would force implementation lanes either to invent contract semantics or to ship paths that violate fixed invariants.
### Blocking findings
1. Health/write authorization can be represented as contradictory, stale, or caller-asserted state.
2. Coordinator failures collapse authoritative denial, unknown transport outcome, and version conflict into one permissive shape.
3. Assignment proposals and approval proofs have no authoritative relational binding; lease acquisition accepts a forgeable proof DTO.
4. Fencing uniqueness is present, but monotonic fencing and same-task lease/checkpoint binding are not.
5. Workspace-safe accountable-owner, assignment-principal, and evidence/artifact relationships are not frozen.
6. Attributable post-recovery proposals have neither a canonical table nor command contract.
7. The slice graph starts schema/UI work before prerequisite threat and exact API/DTO freezes and contradicts coder4 lane order.
8. P0 claims a migration map while publishing only generic rules; the concrete N-1 transition from current `origin/main` is absent.
---
## Findings
### KCR-001 — BLOCKER — “Healthy” is not a proof and can be contradictory or stale
**Location**
- `contracts/health-state.v1.ts:21-31``KanbanHealthResponseV1` permits every combination of `state`, `readHealthProven`, and `writeHealthProven`.
- `contracts/mechanical-coordinator.v1.ts:40-49``CoordinatorContextV1` accepts a caller-supplied `healthState` enum only.
- `contracts/mechanical-coordinator.v1.ts:255-293` — every Coordinator operation, including mutating operations, accepts that context.
- `SHARED-CONTRACT.md:171-184` — mutations are allowed only after live PostgreSQL read/write probes.
**Violation**
Fixed invariant 2 / `REQ-SOT-002`: mutations must fail closed unless write health is positively proven. The current type permits `{ state: 'healthy', writeHealthProven: false }`, and the Coordinator mutation boundary can be invoked with a stale or fabricated `{ healthState: 'healthy' }`. A Valkey/client-derived enum could therefore be mistaken for write authorization.
**Minimal fix**
1. Make `KanbanHealthResponseV1` a discriminated union with only these legal combinations: `healthy => read=true/write=true`, `read-only-degraded => read=true/write=false`, and `write-unavailable => read=false/write=false`.
2. Do not accept write authority from a public DTO. Require Gateway/domain code to obtain and revalidate a fresh internal PostgreSQL write-health proof at mutation time (including `checkedAt`, bounded validity/policy revision, and transaction-local enforcement).
3. Split pure evaluation context from mutation context; mutation methods must accept only an unforgeable/internal healthy context or perform the probe themselves.
4. Add negative contract tests for contradictory state, expired proof, Valkey-only liveness, and caller-forged `healthy`.
### KCR-002 — BLOCKER — Coordinator error shape can conflate denial, unknown outcome, and conflict
**Location**
- `contracts/mechanical-coordinator.v1.ts:184-216` — one `CoordinatorFailureV1` allows every code to pair with arbitrary `retryable` and either `requestOutcome` value.
- `contracts/health-state.v1.ts:51-106` — the Gateway health contract correctly distinguishes deliberate denial, transport uncertainty, and version conflict.
- `SHARED-CONTRACT.md:177-216` — frozen client semantics require those cases not to be conflated.
**Violation**
Charter E and `REQ-SOT-002`. The current Coordinator result can legally encode `WRITE_HEALTH_UNPROVEN` as `retryable: true, requestOutcome: 'unknown'`, or `VERSION_CONFLICT` as retryable. That permits blind retry or a false “unknown” outcome after an authoritative fail-closed denial.
**Minimal fix**
Replace `CoordinatorFailureV1` with a discriminated union keyed by code/kind:
- deliberate health denial: `not_applied`, `retryable:false`;
- version conflict: `not_applied`, `retryable:false`, current version;
- stale fence/session/eligibility/approval failures: exact non-retry semantics;
- transport failure: a separate `retryable_transport_error`, `unknown`, same idempotency key.
Reuse or map explicitly to `KanbanMutationFailureV1`, and add exhaustive client tests proving 503 authoritative bodies, 502/504/timeouts, and 409 cannot cross-map.
### KCR-003 — BLOCKER — Approval proof is forgeable and is not linked to the persisted proposal
**Location**
- `contracts/mechanical-coordinator.v1.ts:107-137` — proposal and approval DTOs.
- `contracts/mechanical-coordinator.v1.ts:265-270``acquireApprovedLease` accepts the entire `ApprovalProofV1` by value.
- `contracts/kanban-schema.v1.ts:650-688``task_assignments` has no proposal expiry, task version, session binding, or proposal/approval FK.
- `contracts/kanban-schema.v1.ts:823-863``approval_decisions` can target only a task or mission and has no proposal/assignment relation.
- `SHARED-CONTRACT.md:128-137` — lease acquisition requires authoritative approval under the exact policy revision.
**Violation**
Fixed invariant 5 and `REQ-COORD-002/003`. A caller can construct an `ApprovalProofV1`; the schema cannot prove that it belongs to the proposal, workspace, task version, agent/session, unexpired policy revision, or still-current approval. The DTO state vocabulary (`awaiting_approval | policy_pre_authorized`) also does not map directly to the persisted assignment states (`proposed | approved | ...`).
**Minimal fix**
Persist one authoritative proposal/assignment identity with task version, target agent/session, expiry, state, and policy revision. Add a workspace-aware approval relation to that identity. Change lease acquisition to accept IDs, then reload and lock proposal + approval + task inside PostgreSQL and verify workspace, current version, target session, state, expiry, and policy revision before creating the lease. Freeze one state vocabulary across schema and DTOs.
### KCR-004 — BLOCKER — Fencing is unique but not monotonically increasing; relational binding is incomplete
**Location**
- `contracts/kanban-schema.v1.ts:694-743``task_leases` has positive/unique fencing tokens but no monotonic per-task counter.
- `contracts/kanban-schema.v1.ts:748-784` — checkpoints independently carry task, lease, and fencing token.
- `contracts/kanban-schema.v1.ts:905-910` — token equality is deferred to prose; same-task lease binding is not stated.
- `contracts/mechanical-coordinator.v1.ts:140-175` — worker commands depend on fencing safety.
**Violation**
Fixed invariant 12 / `REQ-COORD-003`. Uniqueness permits token 10 followed by token 9. A lease can reference assignment A while naming task B in the same workspace, and a checkpoint can reference lease A while naming task B. `bigint(..., { mode: 'number' })` also eventually loses integer precision in JavaScript.
**Minimal fix**
Add a durable per-task fencing counter (or equivalent PostgreSQL sequence row) incremented atomically under task lock and use the returned value for every new lease. Add workspace-aware composite constraints tying lease to its exact task+assignment and checkpoint to exact task+lease+fence. Use bigint-safe representation (`bigint`/serialized decimal), and test monotonicity, concurrent claims, stale lower tokens, and mismatched same-workspace IDs.
### KCR-005 — BLOCKER — Hard tenant boundary is not frozen for several polymorphic relationships
**Location**
- `contracts/kanban-schema.v1.ts:315-318` and `475-478` — project/task accountable owners are unvalidated `(kind, text id)` pairs.
- `contracts/kanban-schema.v1.ts:659-663` — assignment principals are unvalidated `(kind, text id)` pairs.
- `contracts/kanban-schema.v1.ts:758` and `841` — checkpoint/evidence artifact relationships are JSON arrays without workspace-aware FKs.
- `SHARED-CONTRACT.md:89-96` — only selected polymorphic checks are delegated to domain transactions; owner/principal/evidence checks are not included.
- `REQUIREMENTS.md:101-108` — every relationship must reject cross-workspace IDs.
**Violation**
Fixed invariant 7 / `REQ-TEN-001` and `REQ-ID-001`. The frozen schema can name a team or agent from another workspace as owner/assignee, and can embed foreign-workspace artifact IDs in checkpoint or approval evidence arrays. A global user ID is also insufficient without active workspace membership validation.
**Minimal fix**
Use workspace-aware owner/assignment join tables or separate nullable user/team/agent columns with exactly-one checks and composite FKs where possible. Model checkpoint/evidence artifact links as workspace-scoped join rows, or freeze explicit transaction checks for every ID. Require active workspace membership for user principals and workspace-agent/session consistency for agent principals. Add DB/repository/API/Coordinator cross-workspace negative tests without existence oracles.
### KCR-006 — BLOCKER — Post-recovery outage proposals have no canonical persistence or command surface
**Location**
- `REQUIREMENTS.md:93-99` — proposal submission and authorized accept/reject are required.
- `SHARED-CONTRACT.md:26-29` — outage notes may return only as authenticated proposals.
- `SHARED-CONTRACT.md:243-267` — the thin command/query contract contains no proposal submit/get/accept/reject operations.
- `contracts/kanban-schema.v1.ts:1-916` — no proposal table captures proposed command, target/version, attribution, lifecycle, or decision.
- `TASKS.md:99-108` — KBN-110 does not own an outage-proposal command path.
**Violation**
Fixed invariant 4 / `REQ-SOT-004`. An implementation lane would have to invent storage or misuse artifacts/approval gates. Either path risks silently applying an outage note or creating shadow state.
**Minimal fix**
Add a workspace-scoped `change_proposals`/`outage_proposals` contract with authenticated proposer, source note digest, target aggregate, expected version, proposed typed command/payload, pending/accepted/rejected state, decision actor/reason/time, idempotency key, and audit linkage. Add explicit submit/query/accept/reject Gateway commands. Acceptance must execute the normal command in a healthy transaction; a proposal itself can never claim, order, satisfy a gate, or mutate the target.
### KCR-007 — BLOCKER — Parallel slice ordering is not freeze-safe and contains a direct lane-order contradiction
**Location**
- `TASKS.md:43-60` — dependency graph makes KBN-010 and KBN-100 siblings.
- `TASKS.md:88-97` — KBN-100 nevertheless depends on KBN-010 threat findings that alter constraints.
- `SHARED-CONTRACT.md:243` and `INDEX.md:44-50` — exact route names/DTO placement remain unresolved.
- `TASKS.md:110-130` — KBN-120/130 depend on a frozen endpoint/DTO contract, while mocks may begin before KBN-110 lands.
- `TASKS.md:145-153` — KBN-200 says lane-serial after KBN-120.
- `TASKS.md:248-254` — wave table runs KBN-200 before KBN-120.
**Violation**
Charter C and the mandatory freeze-before-parallelize gate. Schema can begin before tenant/threat findings are complete; web/CLI consumers have only semantic operations, not exact DTO/endpoint contracts; coder4 has two opposite legal orders. This does not create same-file edits immediately, but it guarantees contract invention or rework across active lanes.
**Minimal fix**
1. Make KBN-010 (or an explicit constraint-impact gate from it) a completed prerequisite of KBN-100.
2. Add a small serialized KBN-105 endpoint/DTO/endpoint-registry freeze, with exact request/response/error DTOs, before KBN-120 and KBN-130 implementation.
3. Choose one coder4 lane order and use it consistently in slice text, graph, and wave table.
4. Name the exact MCP-owned files or assign their Gateway changes to coder3 before coder4 starts.
### KCR-008 — BLOCKER — Claimed P0 migration map is absent; concrete N-1 hazards remain unresolved
**Location**
- `MISSION-MANIFEST.md:153-157` — P0 says to publish a migration map and states the build hold is lifted at line 3.
- `SHARED-CONTRACT.md:101-121` — only generic expand/backfill/contract rules are supplied.
- `contracts/kanban-schema.v1.ts:1-916` — target-state declarations reuse live table names and make target fields required.
- Current foundation evidence: `origin/main:packages/db/src/schema.ts:120-301` has no workspace keys, nullable project/mission links, legacy text status vocabularies, `tasks.tags`, `tasks.assignee`, `tasks.due_date`, mission JSON milestones/config, `mission_tasks.status`, and legacy agent fields.
**Violation**
Charter D / `REQ-MIG-001` and the P0 exit claim. The generic rule is correct, but coder2 lacks the required field-by-field transition map. A direct Drizzle reconciliation could attempt type narrowing/status conversion, add required workspace/project/owner columns too early, or drop legacy columns before N-1 readers and writers are retired.
**Minimal fix**
Publish a concrete current-main delta map before lifting the hold. For each existing table/column, specify expand, backfill, compatibility read/write, switch, and contract release. At minimum cover:
- nullable-first `workspace_id`, required project/owner fields, and workspace backfill;
- legacy task/project/mission status aliases or shadow columns before v1 emission;
- `mission_tasks.status` read retirement and write-source prohibition;
- mapping/retention for tags, assignee, due date, mission description/config/milestones, and agent fields;
- current milestone circular FK ordering;
- empty, production-shape, partial-resume, and rollback/downgrade tests already named in §4.
Explicitly require legacy columns to remain in the unified Drizzle declaration during the expand/N-1 window.
### KCR-009 — MAJOR — Dependency uniqueness permits parallel duplicate edges
**Location**
- `contracts/kanban-schema.v1.ts:561-567` — unique key includes `dependencyType`.
- `SHARED-CONTRACT.md:47-49` — calls for a unique directed edge.
- `REQUIREMENTS.md:142-149` — duplicate edge attempts must fail.
**Violation**
`REQ-DEP-001`. The same predecessor/successor pair can be inserted three times, once per dependency type. That is not a unique directed edge and complicates readiness semantics.
**Minimal fix**
Make `(workspace_id, predecessor_task_id, successor_task_id)` unique independent of type, or explicitly redefine the requirement as one edge per type and freeze deterministic multi-edge completion semantics. The source plan says unique directed edge, so the former is the minimal faithful fix.
### KCR-010 — MAJOR — Same-workspace planning relationships can contradict the project hierarchy
**Location**
- `contracts/kanban-schema.v1.ts:325``projects.currentMilestoneId` has no FK in the declaration.
- `contracts/kanban-schema.v1.ts:427-448` — mission/milestone association checks workspace but not common project.
- `contracts/kanban-schema.v1.ts:490-516` — a tasks project, mission, milestone, and parent only need share a workspace, not a project.
- `contracts/kanban-schema.v1.ts:905-908` — only current milestone is mentioned as a deferred invariant.
**Violation**
`REQ-PLAN-001` and schema correctness. A task in project A can point to a mission/milestone/parent task from project B in the same workspace. A mission can associate a milestone from another project despite having one required project.
**Minimal fix**
Add project-congruent composite keys/FKs (or freeze mandatory transaction checks) for task→mission, task→milestone, task→parent, mission→milestone, and project→current milestone. Add same-workspace/same-project negative tests.
### KCR-011 — MAJOR — Immutable/append-only records can be erased by parent cascades
**Location**
- `contracts/kanban-schema.v1.ts:798-818``task_events` is described as append-only but remains under a workspace cascade.
- `contracts/kanban-schema.v1.ts:911` — only application-role UPDATE/DELETE privilege removal is stated.
- Numerous canonical relationships use `onDelete('cascade')`, including workspace roots and artifact/checkpoint/event owners.
- `REQUIREMENTS.md:41-43` and `154-170` — audit must be append-only, attributable, and reconstructable.
**Violation**
`REQ-AUD-001`. Revoking direct DELETE on `task_events` does not prevent a parent delete from cascading into the audit log. Checkpoints and immutable artifacts also lack explicit append-only privilege/retention semantics.
**Minimal fix**
Use lifecycle/archive states and `RESTRICT` for canonical parent deletion during normal operation. Freeze a separate, audited retention/break-glass purge procedure. Apply INSERT/SELECT-only or equivalent immutability controls to task events, checkpoints, and immutable artifacts, and test that parent deletion cannot silently erase them.
### KCR-012 — MAJOR — Coordinator persistence lacks durable quarantine/retry state and DTO/schema alignment
**Location**
- `contracts/mechanical-coordinator.v1.ts:239-244` — expiry returns `quarantined` IDs.
- `contracts/kanban-schema.v1.ts:457-490` — task has only untyped `retryPolicy` metadata and no quarantine/execution disposition.
- `contracts/mechanical-coordinator.v1.ts:173``evidenceIds` has no corresponding evidence table/type; schema has artifacts.
- `contracts/kanban-schema.v1.ts:479`, `663`, and agent role JSON — specialist roles are free text despite the frozen role vocabulary in `mechanical-coordinator.v1.ts:19-29`.
**Violation**
`REQ-COORD-004` and internal consistency. PostgreSQL cannot deterministically reconstruct why/when a task was quarantined, its bounded retry state, or which typed evidence was submitted. Free-text roles allow the schema and engine to disagree.
**Minimal fix**
Freeze a durable execution/retry/quarantine record (attempt count, next eligibility, terminal reason, actor/policy, timestamps, version) or typed task columns with events. Align `evidenceIds` to artifact IDs or add a real evidence entity. Use one specialist-role enum/check across tasks, assignments, agents/sessions, DTOs, and Coordinator.
### KCR-013 — MAJOR — Thin MVP promises task archive and tag filtering without target-state semantics
**Location**
- `REQUIREMENTS.md:182-193` — users must archive tasks and filter by tags.
- `SHARED-CONTRACT.md:252-267` — mutations include cancel but not archive task.
- `contracts/kanban-schema.v1.ts:457-490` — no task archive field and no typed tags field/table.
- Current `origin/main` already has `tasks.tags`, making omission from the target declaration a migration-loss hazard.
**Violation**
`REQ-UI-001/002` and internal acceptance consistency. “Archive” cannot be implemented without inventing whether it means cancelled, hidden, or soft-deleted; tag filtering has no frozen storage/query contract.
**Minimal fix**
Either remove task archive/tag acceptance from P1, or add explicit non-lifecycle archival semantics (`archived_at/by/reason`) and a workspace-safe tags model/query contract. Preserve/migrate the current tags column until the selected model is live.
### KCR-014 — MAJOR — Recovery contract states critical rules only in comments and has no owning implementation slice
**Location**
- `contracts/recovery-posture.v1.ts:97-147` — exported JSON Schema validates only local field shapes.
- `contracts/recovery-posture.v1.ts:150-156` — PITR/WAL, effective RPO, off-cluster, high-assurance minima, and audit rules are comments only.
- `REQUIREMENTS.md:270-277` — parser rejection of impossible combinations is acceptance-critical.
- `TASKS.md:75-244` — no bounded slice owns recovery config parsing, override audit, backup/WAL setup, or restore/break-glass evidence.
**Violation**
`REQ-REC-001`. A consumer using the advertised JSON Schema can accept weakened high-assurance values, PITR without WAL, or an impossible RPO. The task plan has no lane accountable for closing that acceptance criterion.
**Minimal fix**
Export a normative `validateRecoveryPostureV1`/schema refinement with machine-testable cross-field checks and add a bounded Infra/recovery slice (serialized if it touches shared config) owning config parsing, override audit, mechanism verification, restore test, and break-glass evidence. Recovery config must continue to expose no authority/gate knobs.
### KCR-015 — MAJOR — Pure Coordinator slice cannot implement two frozen methods without persistence access
**Location**
- `contracts/mechanical-coordinator.v1.ts:259-263``explainEligibility` receives only `taskId`, not a structured snapshot.
- `contracts/mechanical-coordinator.v1.ts:289-293``recoverFromPostgres` explicitly reads PostgreSQL.
- `TASKS.md:145-153` — KBN-200 is a pure engine with no SQL, Drizzle, Gateway, or Valkey.
- `TASKS.md:157-164` — persistence belongs to coder3/KBN-210.
**Violation**
Charter C and internal consistency. coder4 cannot implement the frozen port in a pure package without crossing coder3s persistence boundary. If coder3 implements the port instead, KBN-200s acceptance and ownership are misassigned.
**Minimal fix**
Split the contract into a pure decision engine that receives complete immutable snapshots and a persistence/orchestration service port implemented by KBN-210. Move `recoverFromPostgres` and ID-based loading to the adapter/service; make pure explanation accept a snapshot.
### KCR-016 — MINOR — Health denial code/state pairs are not correlated by type
**Location**
- `contracts/health-state.v1.ts:35-61` — either denial code can pair with either degraded state.
- `SHARED-CONTRACT.md:188-190` — prose defines `KANBAN_WRITE_UNAVAILABLE` specifically for `write-unavailable`.
**Violation**
Health contract precision. A client can receive a semantically inconsistent authoritative body even after KCR-001s broader state fix.
**Minimal fix**
Make deliberate denial a two-variant union with exact code/state pairing.
---
## Clean checks / invariants that do hold
The review did **not** find a gap in these areas:
- The canon consistently selects current `mosaicstack/stack` + Drizzle/PostgreSQL and rejects greenfield/Prisma revival.
- Every artifact states PostgreSQL is the sole writable SOT and Valkey/files are non-authoritative.
- Generated `TASKS.md`, `mission.json`, and exports are consistently declared read-only and never import sources. KBN-300s importer is scoped to immutable legacy JSON/Vikunja snapshots, not generated projections.
- Recovery config exposes recovery fields only; it contains no direct fail-open, SOT, Coordinator-authority, or gate-waiver knob.
- The Coordinator interface contains no `createTask`, acceptance-edit, gate-waive, certify, merge, release, or provider-close method. `submitForReview` is type-limited to `in_review`, not `done` or `certified`.
- Certifier is consistently final independent gate with no merge authority.
- The seven canonical task status values match across requirements, shared prose, schema, and Coordinators ready/in-review surfaces.
- One-active-lease partial uniqueness, no-self-edge, outbox aggregate-revision/event-type uniqueness, optimistic task/project/mission/milestone versions, and N-1 test categories are explicitly present.
- The file-tree partition is mostly well separated once the ordering/freeze defects in KCR-007 are corrected.
## Required re-review scope
After remediation, re-review at minimum:
1. health/coordinator discriminated unions and mutation-time health proof;
2. proposal/approval/assignment/lease relational model;
3. monotonic fencing and composite bindings;
4. tenant-safe polymorphic relationships;
5. outage-proposal persistence and commands;
6. concrete current-main migration map;
7. corrected dependency graph and exact API/DTO freeze;
8. recovery validator/owner slice;
9. all schema and DTO vocabulary alignment.
## Overall verdict
**NO-GO — 8 BLOCKERs must be resolved before the v1 contract is frozen or parallel implementation begins.**

View File

@@ -0,0 +1,38 @@
# #751 Native Kanban/SOT canonical publication — Ultron final gate
**Verdict: GO** — zero BLOCKER/HIGH findings.
## Scope / integrity
- Reviewed `/home/hermes/agent-work/stack-kanban-canon` staged delta only: exactly 16 documentation/contract artifacts; no unstaged delta; `git diff --cached --check` passes.
- This is a publication canon, not a runtime implementation. The explicit implementation hold prevents feature work until canon merge and prerequisite release (`docs/requirements/native-kanban-sot.md:8-9`; `docs/native-kanban-sot/TASKS.md:45-67`).
## Acceptance mapping and findings
| Requirement area | Final evidence / result |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Sole PostgreSQL SOT, generated projections, outage proposals | Requirements D3/D4 and fixed invariants prohibit alternate writers and import (`docs/requirements/native-kanban-sot.md:22-23,32-44`). Health contract keeps public observation separate from branded transaction-local proof (`contracts/health-state.v1.ts:44-84`) and freezes 503/409/502/504 mappings (`:91-184`). Proposal table uses workspace-aware event FKs (`contracts/kanban-schema.v1.ts:847-908`); exact submission/acceptance transaction semantics are specified (`SHARED-CONTRACT.md:81-89`). PASS. |
| Workspace tenancy, planning, assignments, evidence | Workspace-composite task and proposal relations plus active-member rules are explicit (`SHARED-CONTRACT.md:40-48`; `kanban-schema.v1.ts:587-637,875-908`). Lease/checkpoint relations bind workspace/task/assignment/session/fence, with one active lease and bigint fencing (`:1062-1114`). PASS. |
| Coordinator, gates, concurrency/recovery | Pure Coordinator has snapshot-only decision methods (`mechanical-coordinator.v1.ts:186-198`); persistence port owns locked ID validation and recovery (`:371-407`). Requirements forbid Coordinator scope/gate/certification/merge authority and Certifier merge authority (`requirements:39-40`; `MISSION-MANIFEST.md` authority table). Recovery validator rejects unknown fields, PITR/WAL/RPO/storage/high-assurance violations (`recovery-posture.v1.ts:193-369`). PASS. |
| Migration/N-1/API/task decomposition | N-1 expand/backfill/compatibility/switch/contract order and proposal DDL sequence are concrete (`SHARED-CONTRACT.md:69-115`). Frozen exact Gateway/DTO registry and non-overlapping lane ownership/prerequisites are present (`SHARED-CONTRACT.md:244-282`; `TASKS.md:45-67,81-259`). PASS. |
| Documentation / seven owner decisions / evidence | D1D7 are all explicitly ratified (`requirements:20-26`); all 26 REQ sections contain acceptance criteria. Index/manifest/task graph link requirements, frozen contracts, ownership, and evidence. Relative-link audit passes. PASS. |
## Independent verification performed
```text
git diff --cached --check PASS
./node_modules/.bin/prettier --check <all publication paths> PASS
./node_modules/.bin/tsc --noEmit --strict <health/coordinator/recovery> PASS
Python relative Markdown link audit PASS (0 errors)
Python requirement acceptance audit PASS (26 requirements; 0 missing acceptance sections)
Static staged scope/status check PASS (16 staged docs-only; no unstaged delta)
```
The full schema-contract strict type check cannot resolve `drizzle-orm` from this docs-only worktree; this is an environment dependency-resolution limitation, not a contract diagnostic. Independent external publication validation and final re-review record the strict all-four-contract check against the current Stack Drizzle toolchain as PASS.
## Residual items
- **LOW:** implementation must deliver the declared KBN-100/KBN-110/KBN-140 proposal-event-chain, tenant, failure-mapping, and SecReview evidence before P0/P1 release. This is a forward implementation obligation already frozen in the canon, not a publication defect.
- **LOW:** selected infrastructure backup provider/recovery tier and migration/cutover thresholds remain owner-controlled implementation decisions, bounded by the normative recovery contract and change control.
No source, staging, commit, provider, CI, or deployment state was mutated.