Files
stack/docs/native-kanban-sot/KBN-010-THREAT-AUTH-CONSTRAINT-GATE.md
jason.woltje 2e2280070a
All checks were successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
docs(#753): clear KBN-010 threat and schema gate (#765)
2026-07-14 21:46:44 +00:00

74 KiB
Raw Blame History

KBN-010 — Threat, Authorization, and Constraint-Impact Gate

  • Issue: #753
  • Gate status: PASS / GO
  • Reviewed baseline: origin/main at 49e8a54 (2026-07-14)
  • Frozen target: SHARED-CONTRACT.md v1.0.0-rc.4 and contracts/*.v1.ts
  • Disposition input: contract commit 3f6a3387b419eb99453ee10dd25ba888faaab0b5, tree 7ebab8fa530a7180036928cea9527f808548aa14
  • Scope: documentation and future-test planning only; no runtime, schema, migration, API, configuration, dependency, CI, or deployment change

1. Decision

KBN-010 is PASS / GO against frozen contract rc.4. The original rc.3 finding remains historical detection evidence:

  • KBN010-SI-001 — rc.3 invalid mission composite-FK candidate key. At rc.3, missionsV1 declared a primary key on id and a unique key on (workspace_id, project_id, id), but not a candidate key on (workspace_id, id). Both artifacts_workspace_mission_fk and approval_decisions_workspace_mission_fk referenced exactly (missions.workspace_id, missions.id). PostgreSQL requires the referenced column list of a foreign key to match a non-partial unique/primary candidate key; uniqueness of id alone did not satisfy that two-column reference. The rc.3 DDL was therefore invalid, and KBN-010 correctly blocked it.

Contract rc.4 resolves SI-001 by adding the non-partial missions_workspace_id_uidx candidate key on (workspace_id, id) while retaining the global id primary key and the project-congruent (workspace_id, project_id, id) key. Both polymorphic child FKs retain their exact workspace-safe ordered columns and ON DELETE RESTRICT; no target, tenancy, project-congruence, exactly-one-target, N-1, rollback, no-cascade, identity, approval, or fencing authority is weakened.

Independent Homelab non-author schema/security review returned APPROVE for the exact rc.4 commit/tree/content and found no collision with #757 connector fencing. SI-001 has no unresolved contract/schema-design impact.

This GO completes the KBN-010 analysis/review prerequisite only. It does not claim that runtime schema or migration DDL exists. KBN-100 remains held and may be released only after this PR squash-merges, the merged change reaches terminal-green CI on main, and issue #753 closes.

1.1 Independent rc.4 evidence identity

  • Commit: 3f6a3387b419eb99453ee10dd25ba888faaab0b5
  • Tree: 7ebab8fa530a7180036928cea9527f808548aa14
  • Stable full-index SHA-256: 6b40a76265c4f3e6d1d30a7f262a2dd16e0d51997e99c146b59f527e6524cd42
  • Stable patch-id: 058cf98026fcd1043703c866aee047c8bb144740
  • Verdict: Homelab independent non-author schema/security review APPROVE.
  • Reviewed conclusions: the candidate key repairs both dependent FKs; tenant safety, polymorphic exactly-one-target semantics, RESTRICT/no-cascade behavior, and N-1/rollback semantics remain valid; #757 uses separate tables/indexes/FKs/identity/fence authority and has no collision.

A command-rendered patch SHA may differ when Git rendering options, headers, or command form differ. That rendering digest is non-authoritative. Canonical review identity is the Git commit object plus tree and exact file content; the stable full-index digest and stable patch-id above are corroborating identities.

2. Method and trust boundaries

2.1 Inputs inspected

  • Canonical requirements: docs/requirements/native-kanban-sot.md.
  • Workstream manifest and read-only task plan.
  • Frozen health, schema, Mechanical Coordinator, and recovery contracts in full.
  • Actual current-main schema, Better Auth guard/scope helpers, project/task/mission/team controllers and repositories, fleet backlog, and TASKS.md parser/writer.
  • Issue #753 through the Mosaic provider wrapper.

2.2 Current-main exposure that the target must replace, not inherit

Current-main fact Constraint on future implementation
Teams are global; projects, missions, tasks, agents, and fleet backlog have no workspace_id. KBN-100 must add the workspace boundary and KBN-110 must query by server-derived workspace in every repository operation.
AuthGuard authenticates a Better Auth user, while scopeFromUser falls back through optional tenant/team/org claims and finally user ID. Kanban tenancy must derive from an authenticated active workspace membership, not this compatibility fallback or caller data.
Team list/get/member endpoints return global team data to any authenticated user. New Kanban endpoints must use a uniform no-oracle denial and must not reuse global team lookup as authorization.
Project/task repositories load and mutate by bare IDs; controller checks are separate and sometimes distinguish not-found from forbidden. Workspace predicates and authorization must be inside the authoritative transaction/repository command path.
Tasks can have nullable project/mission links, free-text assignee, JSON tags, no aggregate version, and no fence. Expand/backfill/quarantine must precede NOT NULL/composite constraints; new commands cannot trust legacy fields.
mission_tasks.status is a second status writer. Pre-expand must prohibit it as a write source and later retire it only after N-1 evidence.
Fleet backlog has global JSON dependencies and TTL claims without workspace, assignment, approval, session, or fencing. It must be frozen and imported as non-dispatching shadow data; it cannot be adapted into the canonical lease path.
packages/coord/src/tasks-file.ts parses and mutates TASKS.md. KBN-120 must replace production use with generated, read-only projection code and prove there is no import/mutation path.
No Kanban transaction-local health proof, semantic audit/event chain, change proposals, canonical outbox, approval binding, or fenced lease model exists. These are new frozen invariants, not behaviors that may be inferred from current endpoints.

3. Authorization matrix

The exact route/DTO freeze belongs to KBN-105. This matrix fixes the minimum authorization behavior that freeze and later implementation must preserve.

Principal/state Permitted authority Required authoritative checks Explicit denials
Unauthenticated caller Public health observation only, if deployment exposes it Health DTO validation; no proof field accepted All canonical reads/mutations; health observation never authorizes a write
Active workspace owner/admin user Policy-allowed workspace administration and domain commands Better Auth session; active membership; server-derived workspace; command-family role; expected version/idempotency Foreign workspace, suspended workspace, revoked membership, caller workspace override
Active workspace member user Policy-allowed project/task/proposal commands Active membership plus project/team capability and target checks in the same transaction Admin, approval, purge, service-only Coordinator, and unrelated project commands
Active workspace auditor user Workspace-scoped reads and audit/evidence inspection Active membership and read capability Every mutation, approval, lease, token issuance, purge
Active workspace service identity Only explicitly issued command families Credential maps to workspace+agent+session; agent enabled; session live; role/capability allowlist; token expiry/audience; DB recheck per command Raw DB credentials, user/admin fallback, cross-workspace scope, command families absent from token and registry
Enabled agent with live session Agent commands matching its declared and policy-approved specialist role/capabilities Exact workspace+agent+session binding, heartbeat/state, assignment target, lease, current decimal-string fence Ended/offline/degraded session where policy disallows; disabled agent; another assignment/session/fence
Mechanical Coordinator engine Pure eligibility/order/expiry decisions from immutable snapshots Complete workspace-local snapshot and policy revision Authentication, ID loading, SQL, proof minting, scope invention, approval, certification, merge
Coordinator persistence service Service-only assignment/lease/checkpoint/recovery commands Fresh transaction-local proof; locks; current assignment/approval/task/session/policy/fence Public/user proof-by-value, stale approval/policy, direct completion/certification/merge
Reviewer/SecReview/Certifier Attributable evidence decisions allowed by gate policy Active authority, author differs from reviewer, mandatory SecReview classification, immutable artifacts Self-review; missing evidence; Certifier merge/issue-close/release
Break-glass retention operator Narrow, time-bounded purge procedure only Separate break-glass authority, reason, scope, approvals, immutable pre-purge evidence, semantic audit, post-action reconciliation Normal application role DELETE/UPDATE, bulk unscoped purge, unaudited hard delete
Revoked/expired/disabled identity or ended session None beyond policy-permitted public observation Revocation/lifecycle checked from PostgreSQL on every command Cached token/Valkey state cannot preserve authority

No-oracle rule: authentication may return 401, but once authenticated, a foreign-workspace, nonexistent, inaccessible, or wrong-project identifier must follow the one KBN-105-frozen 404/403 policy with the same response shape and no foreign metadata, timing-derived detail, or WebSocket/MCP discrepancy.

4. Threat matrix

Every disposition is against the frozen target, not a claim about current-main behavior.

ID Attacker or failure Asset Precondition and abuse path Frozen preventive/detective control Required schema/API/negative-test evidence Future owner Residual risk Disposition
T01 Authenticated user supplies a foreign workspace/resource ID Tenant confidentiality and integrity Caller knows or guesses project/task/mission/team IDs and probes REST, MCP, WebSocket, repository, or Coordinator paths workspace_id on every canonical row; composite relations; server-derived tenant; uniform no-oracle denial Composite FK/unique DDL; every repository predicate includes workspace; N100-01/02, N110-01..05, N130-01 KBN-100, 105, 110, 130 Timing/volume side channels require operational review Controlled after evidence
T02 Revoked or inactive member retains an old session Ownership and mutation authority Authentication remains valid after workspace membership revocation Active membership rechecked in the authoritative transaction for owners, principals, proposers, and decision actors Active/inactive membership fixtures; N100-03, N110-06/07; no cached membership authority KBN-100, 110 Better Auth session may remain valid for unrelated features Controlled after evidence
T03 User joins/forges a team relation outside its workspace Team-owned projects and tasks Global-current-main team behavior or a stale membership is reused Team is intra-workspace only; workspace/team composites; active workspace membership precedes team authorization Cross-workspace team/member/owner insert and command denials; N100-04/05, N110-08 KBN-100, 110 Team-role policy mistakes remain possible Controlled after evidence
T04 Same-workspace IDs from a different project are combined Planning hierarchy integrity Valid mission/milestone/parent/current-milestone UUIDs are substituted Project-congruent composite relations and serialized hierarchy validation Mission/milestone/parent/current milestone mismatch and parent-cycle tests; N100-06..10, N110-09 KBN-100, 110 Deep hierarchy checks can be expensive Controlled after evidence
T05 Foreign or unrelated evidence/link/artifact IDs are attached Review and audit truth Caller has a valid same-workspace or foreign artifact UUID Workspace-aware joins; immutable artifact digest/revision; semantic same-target validation in authoritative transaction Mixed-workspace and same-workspace wrong-task/mission checkpoint/approval evidence tests; N100-11..14, N210-15/16 KBN-100, 110, 210 Same-workspace semantic validation is application-enforced Controlled after evidence
T06 Stolen, over-scoped, or replayed service token Coordinator and task mutation authority Service credential is accepted as admin/user or claims are trusted without DB state Command-family least privilege; agent/session workspace binding; no raw DB credentials; enabled/live state checked per command Auth registry fixtures prove audience/expiry/role/capability; revoked agent and ended session denials; N105-01, N110-10..13, N210-01/02 KBN-105, 110, 210 Credential theft until expiry/revocation check Controlled after evidence
T07 Caller forges public healthy or replays a stale health response Sole-writer/fail-closed invariant Public health body or caller field reaches mutation context Public DTO is observation only; public DTOs reject proof/health fields; Gateway mints internal proof after live PG transaction probe Contradictory union and forbidden-field tests; N105-02, N110-14..17 KBN-105, 110, 140 Health endpoint can still be used for reconnaissance Controlled after evidence
T08 Internal stale, wrong-policy, or wrong-transaction proof is reused Transaction integrity A branded value leaks or an adapter fails to revalidate it Non-exported brand; transaction identity, checkedAt <= now < validUntil, and policy revision revalidated immediately before mutation Wrong transaction, expiry boundary, future timestamp, policy mismatch, commit-after-expiry tests; N110-18..22 KBN-110, 140 In-process code can bypass TypeScript; runtime checks are mandatory Controlled after evidence
T09 DB/transport uncertainty is mislabeled as deliberate denial or conflict Safe retry and exactly-once result Timeout occurs before/after commit and client changes key or retries 503 Exact 503/502/504/timeout/409 union; unknown outcome retries only with same idempotency key Exhaustive fixture mapping and commit-before-timeout replay; N105-03, N110-23..27, N120-01/02 KBN-105, 110, 120, 140 External client may ignore retry rules Controlled after evidence
T10 Assignment payload forges task version, target agent/session, role, expiry, or proposer Work routing authority Lease service trusts command DTO rather than persisted assignment Persisted assignment identity; exactly-one principal/proposer; exact agent/session composite; acquire accepts IDs then reloads+locks Cross-workspace and same-workspace target substitutions, stale task version, invalid role, expired assignment; N100-15..18, N210-03..08 KBN-100, 200, 210 Compromised authorized proposer can make harmful proposals Controlled by approval/audit
T11 Approval proof is forged by value or borrowed from another assignment Gate integrity Caller submits approved=true, unrelated decision ID, stale policy, or self-approval Relational approval bound to assignment; lock/reload; policy revision; author≠reviewer and mandatory SecReview No proof-by-value DTO; wrong assignment/task/workspace/policy/actor/decision tests; N105-04, N210-09..14, N230-01 KBN-105, 210, 230 Colluding principals remain an organizational risk Controlled after evidence
T12 Revoked policy or expired proposal/assignment is raced against lease acquisition Routing policy Approval and lease transactions do not lock/revalidate current rows Lock assignment, approval, task, target session; compare current policy and expiry inside fresh-proof transaction Concurrent revoke/expire/acquire tests with one valid terminal result; N210-17..19 KBN-210, 230 Clock skew if DB time is not canonical Controlled after evidence
T13 Stale worker sends ack/heartbeat/checkpoint/review after reassignment Canonical task and evidence state Old process retains task/session IDs Task-row-locked atomic monotonic bigint fence; every worker command carries exact lease/session/fence Lower, expired, future, and other-task fences denied; old worker loses after new lease; N100-19/20, N210-20..24 KBN-100, 210, 230 Signed bigint exhaustion is theoretical Controlled after evidence
T14 JavaScript precision truncates a fence Stale-worker exclusion bigint token is serialized as number above 2^53-1 Drizzle bigint and decimal-string wire type only 9007199254740993 and near-int8 boundary round trips; numeric JSON rejected; N105-05, N210-25 KBN-105, 210 Nonconforming external clients Controlled after evidence
T15 Checkpoint/evidence from another lease/task/session is submitted Recovery and certification evidence Same-workspace valid IDs are mixed Exact lease composite binds workspace+task+assignment/session+fence; checkpoint composite binds lease+fence; evidence join plus semantic artifact-owner check Same-workspace mismatched task/assignment/lease/session/checkpoint/artifact tests; N100-21..23, N210-26..31 KBN-100, 210 Artifact URI target may disappear outside DB Controlled with digest/retention
T16 Outage note or pending/rejected proposal mutates/orders work Sole SOT and gate integrity Importer/UI treats note/proposal as task state Proposals are inert; only explicit accept invokes normal typed command after recovery Row/outbox/task counts unchanged for pending/rejected; no readiness/dependency/lease effect; N110-28..31 KBN-110, 140 Humans may act outside Mosaic operationally Accepted as attributable residual
T17 Submission event is missing, foreign, or for another proposal Proposal audit chain Caller supplies an existing event UUID Preallocated proposal ID; event-first same transaction; workspace composite FK; exact event type/aggregate/version semantic check Missing/foreign/wrong-type/wrong-proposal event rolls back event+proposal; N100-24/25, N110-32..36 KBN-100, 110 Semantic checks are transaction code, not only FK Controlled after evidence
T18 Acceptance borrows an unrelated command event Proposal and target integrity Same-workspace event exists for another target/command/proposal Accept locks proposal+target, executes normal command, requires workspace/target match, causation=submission event, payload proposal ID Foreign, wrong target/type/command/causation/payload event aborts target/event/proposal atomically; N100-26, N110-37..43 KBN-100, 110 Event payload schema drift Controlled by KBN-105 fixtures
T19 Application role updates/deletes audit, approval evidence, checkpoint, or artifact Nonrepudiation Broad DB grants or parent cascade exists INSERT/SELECT-only application roles; RESTRICT parent deletes; archive/cancel normal lifecycle Role-level UPDATE/DELETE denied; parent delete RESTRICT; digest unchanged; N100-27..31 KBN-100 DB superuser can alter state Break-glass/infra audit residual
T20 Break-glass purge is used as routine deletion or erases its own evidence Retention and incident forensics Elevated credential available Separate audited retention procedure, bounded scope, reason, pre/post evidence, authority separation Normal role denied; expired/missing approval denied; purge cannot delete its authorizing audit package; N115-01, N230-02/03 KBN-115, 230 Privileged DBA compromise Accepted operational residual
T21 PostgreSQL unavailable or partitioned Canonical state Public health/Valkey remains live while transaction probe fails Fail closed; no alternate writer/hidden queue; 503 only for proven not-applied; transport uncertainty remains unknown Fault injection proves DB rows/outbox/files/Valkey unchanged on deliberate denial; commit-unknown replay; N110-44..48, N140-01 KBN-110, 140, 230 Availability loss is intentional Accepted by Option A
T22 Valkey unavailable, duplicated, stale, or partitioned Scheduling notifications Queue wake is treated as truth or publication fails Valkey derived/expendable; transactional outbox in PG; idempotent publisher; recovery from PG Commit with Valkey down leaves pending outbox; replay publishes once logically; stale wake reloads PG; N110-49, N140-02, N230-04..06 KBN-110, 210, 230 Duplicate at-least-once delivery Consumers must be idempotent
T23 Coordinator restarts between assignment, lease, checkpoint, or outbox steps Durable orchestration truth Process-local cache is treated as authority PostgreSQL stores assignments, execution state, leases, fences, checkpoints, events, outbox; recoverFromPostgres Restart at every transaction boundary reconstructs identical active/expired/pending sets without Valkey/files; N210-32..36, N230-07 KBN-210, 230 Recovery latency Controlled after evidence
T24 Dependency cycle or concurrent reciprocal edge Readiness and dispatch safety Two transactions each see an acyclic graph before inserting Unique directed edge; no self-edge; serialized recursive cycle check; readiness evaluates all blockers Self/duplicate/cycle and concurrent A→B/B→A tests; all predecessor property test; N100-32..35, N200-01/02 KBN-100, 200, 230 Very large DAG performance Bounded operational residual
T25 Parent-task cycle or project-incongruent relation Planning hierarchy Valid same-workspace IDs are arranged into an invalid tree Project-congruent composites; serialized parent-cycle/orphan validation required by REQ-PLAN-001 Self/indirect parent cycle, orphan, and cross-project mission/milestone/parent tests; N100-06..10 KBN-100, 110 Cycle validation is service/transaction enforced Controlled after evidence
T26 Concurrent update, duplicate retry, or idempotency payload drift Aggregate consistency Two clients use same version/key with different payloads Expected-version check; semantic event and outbox in same transaction; key returns prior immutable result only for identical command One update wins; stale gets 409; duplicate identical returns prior; payload drift rejected; N110-50..54, N140-03 KBN-105, 110, 140 Long-lived clients face visible conflicts Intentional user-visible residual
T27 State/event/outbox partial commit Audit and notification consistency Separate transactions or exception after state write One PostgreSQL transaction for state+semantic event+outbox Failure injected after each insert rolls all three back; success revisions align; N110-55..58 KBN-110, 140 Outbox publication remains asynchronous Controlled after evidence
T28 Malicious/incorrect importer injects foreign workspace data or dispatchable work Migration integrity Source keys collide, lineage is absent, or importer has direct DB authority Immutable source snapshots/checksums; one-way Gateway/migration-only port; workspace-safe idempotent modes; shadow records cannot dispatch Foreign/malformed/duplicate/partial-resume/lineage checksum and no-dispatch tests; N300-01..08 KBN-300, 330 Source data may be semantically ambiguous Quarantine and owner sign-off
T29 Cutover leaves legacy writer or forward/reverse sync active Sole-writer invariant Credentials/processes survive switch or rollback is improvised Writer inventory, freeze, final delta, Gateway switch, credential shutdown, no dual write; rollback authority changes after first DB mutation Process/credential inventory; concurrent-writer assertion; before/after-mutation rollback rehearsal; N320-01..06, N330-01 KBN-320, 330, 340 Missed external automation Owner-gated residual
T30 Generated TASKS.md/mission.json is edited or parsed into DB Canonical state Current-main parser/writer remains reachable or file watcher imports changes Generated non-authoritative header/IDs/time/revision; no production importer; regenerate/overwrite only Static import search, tamper/regeneration, read-only permission, source-revision parity; N120-03..07, N140-04 KBN-120, 140 Humans may mistake snapshots for live data Header and docs mitigate
T31 N-1 compatibility copies legacy ambiguity into canonical authority Data integrity Nullable/global/current-main fields are guessed during backfill Nullable-first expand; deterministic mapping or quarantine; checksums; no new-only status before switch; legacy fields retained Production-shape, ambiguous owner/assignee, status shadow, JSON/config/digest, rollback tests; N100-36..44 KBN-100 Quarantined records require human decision Controlled by signed reconciliation
T32 Recovery posture claims durability not provided by mechanisms Availability and audit retention Shape-only validation or optimistic RPO is accepted Normative validator; WAL/PITR/RPO/storage/high-assurance constraints; mechanism and restore evidence Unknown/impossible/weakened configuration plus actual mechanism/restore tests; N115-02..08 KBN-115 Backup operator or storage compromise Separate failure domain residual
T33 rc.3 frozen DDL could not create mission-scoped evidence/approval FKs Tenant/evidence relational integrity KBN-100 generated DDL from the rc.3 contract without an exact composite candidate key rc.4 adds non-partial missions_workspace_id_uidx(workspace_id,id) before both dependent FKs while retaining global and project-congruent keys KBN-100 must execute N100-45..50: exact-key reconciliation, candidate-before-FKs, duplicate feasibility, empty/prod/N-1/rollback, and both-child foreign-workspace negatives KBN-100 after PR/CI/#753 release Runtime DDL remains unimplemented and must prove the frozen order Resolved by rc.4 + independent APPROVE; implementation evidence remains required

5. Constraint-impact matrix

Impact ID Required invariant Frozen schema impact API/transaction impact Required evidence Owner Status
CI-01 Hard workspace tenancy and no oracle workspace_id, workspace-aware unique/FKs on all canonical rows Server-derived workspace; uniform denial on all surfaces N100-01..14; N110-01..09; N130-01 KBN-100/105/110/130 Resolved by frozen controls
CI-02 Active user membership Membership row plus unique (workspace_id,user_id); active state retained Recheck active membership in same authoritative transaction N100-03; N110-06/07 KBN-100/110 Resolved; not FK-only
CI-03 Service identity least privilege/revocation Agent/session workspace, lifecycle, state, roles, capabilities Token maps to exact agent/session; command-family allowlist; DB recheck; no admin/raw DB fallback N105-01; N110-10..13; N210-01/02 KBN-105/110/210 Resolved at auth/API layer
CI-04 Project-congruent hierarchy Composite project/mission/milestone/parent/current-milestone relations Lock/serialized parent-cycle and orphan validation N100-06..10 KBN-100/110 Resolved; cycle behavior required
CI-05 Health-proof authority Internal branded proof has transaction/time/policy fields Probe and revalidate on same PG transaction; no public field N105-02/03; N110-14..27 KBN-105/110 Resolved by frozen controls
CI-06 Assignment/approval identity Exactly-one principal/proposer, exact agent/session assignment, relational approval Reload+lock all IDs; compare version/target/state/expiry/policy/decision N100-15..18; N210-03..19 KBN-100/210 Resolved by frozen controls
CI-07 Monotonic bigint fencing Durable bigint counter, exact lease/fence keys, one active lease Atomic increment/RETURNING; decimal-string DTO; reject every stale worker command N100-19..23; N210-20..31 KBN-100/105/210 Resolved by frozen controls
CI-08 Proposal event chain Both workspace-aware event FKs; event table created first Exact submission/acceptance semantic checks in one transaction N100-24..26; N110-28..43 KBN-100/110 Resolved; semantic checks not FK-only
CI-09 Immutable audit/evidence retention RESTRICT parents; INSERT/SELECT-only immutable tables Archive/cancel normal flow; separately authorized purge N100-27..31; N115-01; N230-02/03 KBN-100/115/230 Resolved by frozen controls
CI-10 DB/Valkey/outbox/restart semantics PG outbox and durable orchestration rows Fail closed; same-key uncertainty retry; Valkey reloads PG; restart from PG N110-44..49; N140-01/02; N230-04..07 KBN-110/210/230 Resolved by frozen controls
CI-11 DAG/race/idempotency/version Unique edge; self check; event idempotency; aggregate versions Serialized recursive cycle check; payload binding; expected-version conflict N100-32..35; N110-50..58; N200-01/02 KBN-100/110/200 Resolved by frozen controls
CI-12 Import/cutover trust boundary Lineage/artifact/event fields; shadow state cannot dispatch One-way scoped importer, freeze, no direct DB/file authority, no dual writer N300-01..08; N320-01..06 KBN-300/320/330 Resolved by frozen controls
CI-13 Generated-file no-import No canonical file schema/import contract Projection-only package; static reachability check removes current parser from production Kanban paths N120-03..07; N140-04 KBN-120/140 Resolved by frozen controls
CI-14 Mission-scoped artifact and approval FKs rc.4 adds non-partial missions_workspace_id_uidx(workspace_id,id) and retains global/project-congruent keys KBN-100 must emit the candidate before both exact RESTRICT FKs and preserve N-1/rollback order N100-45..50: exact reconciliation, duplicate feasibility, empty/prod/N-1/rollback, and separate artifact/approval foreign-workspace negatives KBN-100 after PR/CI/#753 release Resolved by rc.4 and independent APPROVE; future executable evidence required

6. Exact future negative-test catalog

These names are normative evidence identifiers for future slices. Equivalent test-file names are acceptable only if traceability retains these IDs and expected outcomes.

KBN-100 — schema and migration

  • N100-01 reject every canonical child row whose workspace_id differs from its parent.
  • N100-02 reject foreign-workspace link, artifact, proposal target, dependency, assignment, lease, checkpoint, approval, and event relationships.
  • N100-03 reject an inactive/revoked member as accountable owner, proposer, decision actor, archive actor, or user principal in the authoritative command transaction.
  • N100-04 reject a team/project relation crossing workspaces.
  • N100-05 reject a team authorization path when the user lacks active membership in the team's workspace.
  • N100-06 reject task→mission project mismatch.
  • N100-07 reject task→milestone and project→current-milestone project mismatch.
  • N100-08 reject task→parent project mismatch and self-parent.
  • N100-09 reject indirect parent cycles under concurrent transactions.
  • N100-10 reject mission→milestone project mismatch/orphan.
  • N100-11 reject checkpoint artifact from another workspace.
  • N100-12 reject checkpoint artifact owned by another same-workspace task/mission unless an explicitly frozen evidence rule permits it.
  • N100-13 reject approval evidence from another workspace.
  • N100-14 reject same-workspace approval evidence unrelated to the approval target.
  • N100-15 reject zero/multiple assignment principals and zero/multiple proposers.
  • N100-16 reject target session without its exact target agent.
  • N100-17 reject assignment task/agent/session crossing workspaces.
  • N100-18 reject non-positive task version and expired assignment acquisition.
  • N100-19 concurrent lease insert permits one active lease and returns one winner.
  • N100-20 successive leases return strictly increasing bigint fences.
  • N100-21 reject checkpoint with another task, lease, or fence.
  • N100-22 reject duplicate/non-monotonic checkpoint sequence.
  • N100-23 reject evidence join for a mismatched checkpoint/task.
  • N100-24 proposal insert without exact submission event fails atomically.
  • N100-25 foreign/wrong-type/wrong-proposal submission event fails atomically.
  • N100-26 foreign/wrong-target/unrelated acceptance event fails atomically.
  • N100-27 application role cannot UPDATE/DELETE task_events.
  • N100-28 application role cannot UPDATE/DELETE checkpoints/artifacts/evidence joins.
  • N100-29 parent hard delete is RESTRICTed while audit/evidence children exist.
  • N100-30 archive does not alter canonical lifecycle status.
  • N100-31 purge without break-glass authority/evidence is denied.
  • N100-32 reject dependency self-edge and duplicate directed pair regardless of type.
  • N100-33 reject direct and indirect dependency cycles.
  • N100-34 concurrent reciprocal dependency inserts cannot both commit.
  • N100-35 readiness remains false until every blocking predecessor and completion condition passes.
  • N100-36 empty DB migration succeeds after the contract amendment.
  • N100-37 production-shape expand retains all legacy declarations.
  • N100-38 crash/resume backfill is idempotent and checksum-stable.
  • N100-39 ambiguous workspace/owner/assignee is quarantined, never guessed.
  • N100-40 no ready/in_review status is emitted to N-1 readers before switch.
  • N100-41 mission_tasks.status cannot remain a write source.
  • N100-42 tags/assignee/date/mission JSON/config/description/agent fields reconcile without loss.
  • N100-43 claimed fleet backlog rows are quarantined and imported rows cannot dispatch.
  • N100-44 pre-switch rollback works while post-first-mutation rollback requires freeze/reconciliation.
  • N100-45 reconcile both exact child FK column lists to the rc.4 (workspace_id,id) mission candidate while retaining the global id primary key and (workspace_id,project_id,id) key.
  • N100-46 empty-DB migration creates missions_workspace_id_uidx before artifacts_workspace_mission_fk and approval_decisions_workspace_mission_fk.
  • N100-47 production-shape preflight finds no duplicate (workspace_id,id) groups, preserves global id uniqueness, and applies the candidate before both dependent FKs.
  • N100-48 N-1 startup/read/write remains unchanged; pre-switch rollback drops both dependents before the candidate and preserves the global/project-congruent keys.
  • N100-49 artifact insert using a valid mission ID paired with a foreign workspace fails before commit.
  • N100-50 approval-decision insert using a valid mission ID paired with a foreign workspace fails before commit.

KBN-105/KBN-110/KBN-120/KBN-130/KBN-140 — API and P1

  • N105-01 every route has an explicit user/service command-family policy; user/admin tokens cannot call service-only Coordinator mutations.
  • N105-02 public DTO validation rejects writeProof, internal context, body workspaceId, and caller-asserted health.
  • N105-03 fixture exhaustiveness prevents 503, 502/504/timeout, and 409 cross-mapping.
  • N105-04 approval DTO accepts an ID and decision command only, never approval proof-by-value.
  • N105-05 all fence fields accept/emit decimal strings and reject JSON numbers.
  • N110-01 listing with a foreign workspaceId or foreign filter ID follows the frozen no-oracle denial and returns no rows/counts/cursors.
  • N110-02 get by foreign or nonexistent aggregate ID has the same frozen denial shape and no foreign metadata.
  • N110-03 create/update/archive with a foreign owner, parent, project, mission, milestone, tag, or target ID is denied before mutation.
  • N110-04 dependency/proposal commands with foreign target IDs are denied with unchanged state/event/outbox counts.
  • N110-05 REST, MCP, WebSocket, and internal Coordinator paths produce equivalent no-oracle behavior for the same foreign ID.
  • N110-06 a revoked/inactive owner is denied even with a still-valid Better Auth session.
  • N110-07 stale membership/team cache cannot authorize a proposer, decision actor, archive actor, or principal after revocation.
  • N110-08 a team ID from another workspace cannot authorize or own the command target.
  • N110-09 same-workspace but wrong-project mission/milestone/parent IDs are denied inside the transaction.
  • N110-10 an expired service token is denied before repository access.
  • N110-11 an audience- or workspace-mismatched service token is denied without an existence oracle.
  • N110-12 an over-scoped service token cannot call a command family absent from its role/capability allowlist.
  • N110-13 disabled agent or ended session revokes service-token command authority immediately on PostgreSQL recheck.
  • N110-14 contradictory public health state/boolean combinations fail validation.
  • N110-15 Valkey-only liveness cannot mint or substitute a PostgreSQL write proof.
  • N110-16 caller-forged public healthy cannot enter internal mutation context.
  • N110-17 public REST/MCP/CLI bodies containing health/proof fields are rejected.
  • N110-18 an expired internal proof produces no state/event/outbox write.
  • N110-19 a future-dated or not-yet-valid proof produces no write.
  • N110-20 a policy-revision-mismatched proof produces no write.
  • N110-21 a proof minted on another transaction/connection produces no write.
  • N110-22 a proof that expires before the final pre-mutation check produces no write.
  • N110-23 deliberate read-only/write-unavailable denial maps only to authoritative 503/not-applied/non-retryable.
  • N110-24 timeout before commit maps to transport-unknown and permits only same-key retry.
  • N110-25 timeout after commit maps to transport-unknown and same-key retry returns the committed canonical result once.
  • N110-26 expected-version mismatch maps only to 409/not-applied/non-retryable.
  • N110-27 recovery replay with a changed idempotency key cannot masquerade as the original uncertain request.
  • N110-28 pending proposal cannot alter target fields/status/rank/version.
  • N110-29 rejected proposal cannot affect readiness, dependencies, or gates.
  • N110-30 pending/rejected proposal cannot create an assignment or lease.
  • N110-31 direct proposal-row state manipulation cannot bypass normal command execution.
  • N110-32 proposal submission without a submission event rolls back fully.
  • N110-33 foreign-workspace submission event rolls back fully.
  • N110-34 wrong aggregate/event type submission event rolls back fully.
  • N110-35 same-workspace event for another proposal rolls back fully.
  • N110-36 submission event with wrong previous/new version semantics rolls back fully.
  • N110-37 foreign-workspace acceptance event rolls back proposal, target, event, and outbox.
  • N110-38 same-workspace event for another target aggregate rolls back acceptance.
  • N110-39 event from an unrelated normal command rolls back acceptance.
  • N110-40 event caused by a different submission event rolls back acceptance.
  • N110-41 event whose payload lacks or changes changeProposalId rolls back acceptance.
  • N110-42 event for another proposal with the same target/command rolls back acceptance.
  • N110-43 missing accepted-command event after target handling rolls back the entire transaction.
  • N110-44 read-only-degraded denial changes no DB row/outbox/file/Valkey/provider state.
  • N110-45 write-unavailable denial changes no DB row/outbox/file/Valkey/provider state.
  • N110-46 PostgreSQL disconnect cannot redirect a command to any fallback writer.
  • N110-47 commit uncertainty remains unknown and never becomes a fabricated 503/not-applied result.
  • N110-48 same-key replay after recovery returns one canonical result with no duplicate event/outbox row.
  • N110-49 Valkey publication failure leaves committed PG outbox pending and replayable.
  • N110-50 two same-version updates produce one winner and one visible 409 loser.
  • N110-51 identical duplicate key+payload returns the prior immutable result without another event/outbox row.
  • N110-52 same key with payload/command drift is rejected as an idempotency conflict.
  • N110-53 the same key in another workspace cannot reveal or reuse the first workspace's result.
  • N110-54 stale reconnect/update cannot silently overwrite a newer aggregate revision.
  • N110-55 failure after state write but before semantic event rolls back state.
  • N110-56 failure after semantic event but before outbox rolls back state and event.
  • N110-57 failure after outbox insert but before commit rolls back state, event, and outbox.
  • N110-58 success commits matching aggregate/event/outbox revisions and correlation/causation.
  • N120-01 CLI never retries an authoritative 503 deliberate denial.
  • N120-02 CLI retries only transport-unknown outcomes and preserves the exact idempotency key.
  • N120-03 generated projection header contains non-authoritative warning, workspace/project IDs, generated time, and source revision.
  • N120-04 projection revision and records match the API snapshot revision exactly.
  • N120-05 hand-tampering is overwritten or rejected by regeneration and never mutates PostgreSQL.
  • N120-06 static/runtime reachability finds no parser/import path from TASKS.md, mission.json, or another export.
  • N120-07 projection writer has no domain mutation/raw SQL/Valkey authority.
  • N130-01 UI foreign/no-access/not-found state follows the frozen no-oracle response and renders no stale foreign data.
  • N140-01 real-Gateway DB fault journey proves fail-closed no-fallback behavior.
  • N140-02 real-Gateway Valkey-loss journey proves pending outbox replay.
  • N140-03 real-Gateway concurrent update/retry journey proves version and idempotency semantics.
  • N140-04 generated-file tamper journey proves projection parity and no import.

KBN-115/KBN-200/KBN-210/KBN-230 — recovery and coordination

  • N115-01 retention purge without current break-glass authority, reason, immutable evidence, or bounded scope is denied and audited.
  • N115-02 recovery posture with an unknown top-level or storage field is rejected.
  • N115-03 PITR retention without WAL archival is rejected.
  • N115-04 WAL archival with zero PITR retention is rejected.
  • N115-05 claimed RPO better than the configured backup/WAL mechanism is rejected.
  • N115-06 unencrypted, optional, or same-failure-domain storage is rejected.
  • N115-07 weakened high-assurance values are rejected.
  • N115-08 shape-only validation cannot pass without normative mechanism and restore evidence.
  • N200-01 cyclic/incomplete dependency snapshots never become eligible.
  • N200-02 identical immutable snapshot+policy+time returns identical ordering and explanation with no I/O/model import.
  • N210-01 disabled agent cannot claim, ack, heartbeat, checkpoint, or submit review.
  • N210-02 ended/offline/mismatched session cannot claim, ack, heartbeat, checkpoint, or submit review.
  • N210-03 foreign-workspace task is rejected after lock/reload without an oracle.
  • N210-04 stale task version is rejected before fence increment.
  • N210-05 assignment target agent mismatch is rejected.
  • N210-06 target session mismatch is rejected.
  • N210-07 expired assignment is rejected.
  • N210-08 assignment in rejected/released/expired/superseded/leased-invalid state is rejected.
  • N210-09 missing approval is rejected.
  • N210-10 rejected/escalated/requested approval is rejected as approval authority.
  • N210-11 stale policy-revision approval is rejected.
  • N210-12 foreign-workspace approval is rejected without an oracle.
  • N210-13 approval for another assignment is rejected.
  • N210-14 author self-approval/review is rejected when independence is required.
  • N210-15 foreign-workspace artifact evidence is rejected.
  • N210-16 same-workspace artifact unrelated to the assignment/task/gate is rejected.
  • N210-17 concurrent policy revocation versus acquire cannot produce a lease under the revoked revision.
  • N210-18 concurrent assignment expiry versus acquire cannot produce a lease after expiry.
  • N210-19 concurrent session end versus acquire cannot produce a lease for the ended session.
  • N210-20 lower fencing token is rejected without writes.
  • N210-21 token from an older lease is rejected without writes.
  • N210-22 token paired with another task is rejected without writes.
  • N210-23 token paired with another session is rejected without writes.
  • N210-24 token on an expired/revoked/released lease is rejected without writes.
  • N210-25 fences above JavaScript safe integer round-trip exactly as decimal strings.
  • N210-26 lease task does not match assignment task and is rejected.
  • N210-27 lease agent/session does not match assignment target and is rejected.
  • N210-28 checkpoint task does not match lease task and is rejected.
  • N210-29 checkpoint fence does not match exact lease fence and is rejected.
  • N210-30 checkpoint sequence duplicate/regression is rejected.
  • N210-31 checkpoint artifact does not match workspace/task/evidence semantics and is rejected.
  • N210-32 restart after assignment persistence reconstructs the pending assignment.
  • N210-33 restart after lease commit reconstructs exact active lease and fence.
  • N210-34 restart after checkpoint commit reconstructs checkpoint/recovery state.
  • N210-35 restart during expiry/retry/quarantine reconstructs durable disposition and eligibility.
  • N210-36 restart with pending outbox reconstructs publication work without Valkey/files.
  • N230-01 author=self-review and missing mandatory SecReview cannot certify or complete.
  • N230-02 normal application role cannot execute retention purge.
  • N230-03 break-glass purge cannot delete or alter its own authorization/evidence chain.
  • N230-04 Valkey down leaves canonical work in PostgreSQL/outbox.
  • N230-05 duplicate wake produces one logical effect after PostgreSQL reload/idempotency.
  • N230-06 stale wake cannot revive an expired/revoked assignment or lease.
  • N230-07 restart with no Valkey/files reconstructs leases/retry/quarantine/outbox exactly.

KBN-300/KBN-320/KBN-330/KBN-340 — migration and cutover

  • N300-01 source record targeting another workspace is denied/quarantined without an oracle.
  • N300-02 malformed source record is rejected with attributable reject evidence.
  • N300-03 duplicate source system/key/batch replay is idempotent.
  • N300-04 source snapshot/checksum drift aborts apply/verify.
  • N300-05 partial import resumes from durable lineage without duplicating state/events.
  • N300-06 imported shadow record cannot become ready, assigned, or leased automatically.
  • N300-07 missing source key/file/checksum/batch lineage prevents apply/sign-off.
  • N300-08 importer cannot use direct DB, generated file, Valkey, or provider issue as canonical write authority.
  • N320-01 cutover without a verified write freeze fails safe.
  • N320-02 active legacy writer process or credential blocks cutover.
  • N320-03 reverse and forward synchronization cannot run concurrently.
  • N320-04 failed final delta/reconciliation blocks client switch.
  • N320-05 rollback before first canonical DB mutation may switch authority back only after freeze assertion.
  • N320-06 rollback after first canonical mutation requires freeze, DB-delta export/reconciliation, and owner decision.
  • N330-01 rehearsal cannot sign off while counts/checksums/exceptions/writer inventory differ.
  • N340-01 cutover cannot proceed without owner authorization, terminal evidence, scoped identities, and zero active legacy writers.

7. Requirements traceability

Requirement Threats/impacts Planned evidence
REQ-SOT-001 T16, T21, T22, T27, T29, T30 N110-28..31, N110-44..49, N110-55..58, N120-03..07, N320-01..06
REQ-SOT-002 T07, T08, T09, T21 N105-02/03, N110-14..27, N110-44..48
REQ-SOT-003 T30 N120-03..07, N140-04
REQ-SOT-004 T16..18 N100-24..26, N110-28..43
REQ-TEN-001 T01..05, T15, T33 N100-01..14, N100-45..50, N110-01..09, N210-15/16
REQ-ID-001 T02, T03, T06, T10..12 N105-01, N110-06..13, N210-01..19
REQ-PLAN-001 T04, T25 N100-06..10
REQ-TASK-001 T13, T26, T31 N100-20, N100-37..42, N110-50..54
REQ-TASK-002 T16, T24 N110-28..31, N100-35, N200-01
REQ-DEP-001 T24 N100-32..35, N200-01
REQ-ASN-001 T10..12 N100-15..18, N210-03..19
REQ-AUD-001 T17..20, T22, T27 N100-24..31, N110-32..43, N110-49, N110-55..58
REQ-API-001 T01, T06..18, T26 N105-01..05 plus KBN-110 catalog
REQ-UI-002/003 T01, T15, T26 N130-01 and real-Gateway KBN-140 journeys
REQ-COORD-001 T22..24 N200-01/02, N210-32..36
REQ-COORD-002 T10..12, T16 N210-03..19, N110-28..31
REQ-COORD-003 T13..15, T23 N100-19..23, N210-20..36
REQ-COORD-004 T23, T26 N210-32..36, N230-07
REQ-GATE-001/002 T11, T19, T20 N210-09..14, N230-01..03
REQ-REC-001 T20, T32 N115-01..08
REQ-MIG-001/002 T28, T29, T31 N100-37..44, N300-01..08, N320-01..06, N330-01, N340-01

REQ-UI-001 and REQ-UI-004 are downstream functional/accessibility requirements rather than schema-threat controls; they remain owned by KBN-130/KBN-140. Their security-relevant tenancy, conflict, and stale-reconnect portions are covered above.

8. Issue #753 acceptance mapping

Issue requirement/criterion Evidence in this document Result
Cross-workspace owners, principals, evidence, project hierarchy T01T05, T15, T25; CI-0104 Mapped
Active membership and service-token boundaries Authorization matrix; T02, T03, T06; CI-02/03 Mapped
Stale/forged health and transaction-local proof T07T09, T21; CI-05 Mapped
Assignment/approval forgery and monotonic fencing T10T15; CI-06/07 Mapped
Change-proposal abuse and event binding T16T18; CI-08 Mapped
Immutable audit and break-glass T19/T20; CI-09 Mapped
PostgreSQL/Valkey failures T21T23; CI-10 Mapped
Dependency/idempotency/version races T24T27; CI-11 Mapped
Import/cutover and generated-file boundary T28T31; CI-12/13 Mapped
Every schema/API/test impact explicit Constraint matrix and negative-test catalog Mapped
No unresolved schema impact CI-14; rc.4 resolved-impact record PASS — none unresolved
Independent SecReview Homelab non-author exact commit/tree/content review PASS / APPROVE
PR merge, terminal-green main CI, and #753 closure Orchestrator-owned post-worker gates Pending; KBN-100 remains held until completion

9. UNRESOLVED SCHEMA IMPACTS

none

Resolved-impact record — KBN010-SI-001

  • Historical detection: rc.3 lacked an exact (workspace_id,id) candidate key for the artifact and approval-decision mission FKs. This document's original BLOCKED verdict was correct and remains preserved in §1 and T33.
  • Resolution: rc.4 adds non-partial missions_workspace_id_uidx(workspace_id,id) before both exact dependent FKs while retaining the global primary key and project-congruent key.
  • Reviewed object: commit 3f6a3387b419eb99453ee10dd25ba888faaab0b5, tree 7ebab8fa530a7180036928cea9527f808548aa14.
  • Corroborating identities: full-index SHA-256 6b40a76265c4f3e6d1d30a7f262a2dd16e0d51997e99c146b59f527e6524cd42; stable patch-id 058cf98026fcd1043703c866aee047c8bb144740.
  • Independent verdict: Homelab non-author schema/security review APPROVE. It confirmed PostgreSQL candidate/FK validity, unchanged tenant and polymorphic exactly-one-target safety, RESTRICT/no-cascade semantics, N-1/rollback validity, and no shared table/index/FK/identity/fence authority collision with #757.
  • Digest interpretation: a command-rendered patch digest varied with rendering command/options and is non-authoritative. Git commit + tree + exact file content are canonical; stable full-index SHA-256 and stable patch-id corroborate that identity.
  • Residual implementation obligations: KBN-100 must create the candidate before both dependent FKs; prove production-shape duplicate feasibility without weakening global uniqueness; pass empty/prod/N-1/rollback tests; reconcile both exact FK targets; and separately reject foreign-workspace mission references for artifacts and approval decisions (N100-45..50).
  • Implementation status: no runtime schema, migration, API, or deployment implementation is claimed by this gate disposition.

10. Residual risk and handoff

  • Active membership, polymorphic targets, same-task evidence semantics, parent/DAG cycle checks, token scope, and no-oracle behavior depend on authoritative transaction code and must not be treated as FK-only guarantees.
  • DB superuser and break-glass compromise cannot be eliminated by application constraints; separation of duties, immutable external backup/audit evidence, drills, and monitoring remain required.
  • PostgreSQL unavailability intentionally sacrifices writes for integrity. Transport-unknown outcomes remain safe only when clients preserve the exact idempotency key.
  • Imported ambiguous records remain quarantined until owner sign-off; no automated mapping may convert ambiguity into authority.
  • SI-001 is resolved at frozen contract/design-review level only. KBN-100 still owes N100-45..50 executable migration evidence.

Handoff status: KBN-010 PASS / GO at rc.4. KBN-100 remains held until this PR squash-merges, terminal-green CI completes on main, and issue #753 closes; the orchestrator owns those remaining gates.