Skip to content

feat: IM-7 — Cluster A invite marker + optional/non-blocking closure#253

Merged
jukka-matti merged 8 commits into
mainfrom
im-7-cluster-a-closure
May 30, 2026
Merged

feat: IM-7 — Cluster A invite marker + optional/non-blocking closure#253
jukka-matti merged 8 commits into
mainfrom
im-7-cluster-a-closure

Conversation

@jukka-matti
Copy link
Copy Markdown
Owner

IM-7 (spec §9 + §11 #6). Project = collaboration; closure is optional, non-blocking, hidden-solo.

What changed

  • ImprovementProject.collaboratedAt? — durable marker set once on first invite, never cleared (gates Azure collaboration surfaces; not a reversible members.length>1). New isCollaborative(ip) predicate.
  • Sign-off reshaped: optional + non-blocking; hidden unless collaborative AND sign-off callbacks are wired (PWA wires none → never shown, honoring hidden-vs-disabled; Azure wires all three → shown). Decoupled from processOwner (any acting user approves). ProcessHub.processOwner retained for its other uses.
  • §11 chore(deps-dev): bump vite-plugin-pwa from 0.21.2 to 1.2.0 #6 reconciled: IP.signoff is canonical; ControlHandoff.signoff + CONTROL_HANDOFF_SIGNOFF deleted (zero UI dispatch — dead scaffolding); the two read consumers re-pointed to handoff status/acknowledgedAt; exhaustive union preserved.
  • ACL untouched (member===sponsor, no approve-*; Sponsor = identity label).
  • Apply-phase docs: de-gatekeeper personas + ia-nav-model + product-overview; Sustainment→Control (presentation-only); new flows/pwa-solo-investigation.md; decision-log §11 chore(deps-dev): bump vite-plugin-pwa from 0.21.2 to 1.2.0 #6.

Verification

  • Full pr-ready-check green (on the main-merged state).
  • 4-dimension adversarial review (fix-then-merge): fixed the PWA hidden-vs-disabled sign-off (gate on callbacks-present) + the missed product-overview.md de-gatekeeper + doc-terminology fragments. Core sound: exhaustive union holds, consumers re-pointed, marker set-once/never-cleared dual-tested.

🤖 Generated with Claude Code

jukka-matti and others added 8 commits May 30, 2026 15:20
Add a durable collaboratedAt?: number root field to ImprovementProject,
set ONCE on the first invite (roster grows beyond the solo creator) at both
ProjectsTabView onMembersChange set-sites and NEVER cleared on removal.
Threads the existing component-stable now (no bare Date.now() in the testable
path). Adds an isCollaborative(ip) = Boolean(ip.collaboratedAt) predicate that
gates the Azure-only collaboration affordances. The patch type already permits
the new optional root field, and the IMPROVEMENT_PROJECT_UPDATE reducers carry
it through via ...patch — no action-union or IDB change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
IPDetailTeamRail now gates the sign-off section behind isCollaborative(ip):
solo projects (no collaboratedAt) hide it entirely — a solo investigation
closes without sign-off. Sign-off is decoupled from the process owner and is
never a hard gate to close: canApprove = pendingSignoff (no processOwner
requirement), and the pending copy reads a generic 'Awaiting approval' rather
than naming a gatekeeper. The approver identity is captured at the dispatch
site: Azure ProjectsTabView resolves the acting user from project membership
(actingApprover), falling back to a generic Reviewer ref — never the process
owner. PWA wires no sign-off callbacks at all (Mode-1 solo, §9.2) and its
nudge stub is removed. ProcessHub.processOwner is retained (independent uses).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…al (IM-7 §11 #6)

Surface B (ControlHandoff.signoff + the CONTROL_HANDOFF_SIGNOFF action) had
zero UI dispatch and duplicated the wired, canonical IP.signoff lifecycle.
Atomic discriminated-union cascade in one coherent change so the tree never
holds a broken union:

- control.ts: drop ControlHandoff.signoff + its now-unused
  ImprovementProjectSignoff import.
- controlHandoffActions.ts: drop the CONTROL_HANDOFF_SIGNOFF action arm, the
  'signoff' key from the CONTROL_HANDOFF_UPDATE Omit, and the unused import.
- applyAction.ts (azure + pwa): drop the CONTROL_HANDOFF_SIGNOFF reducer arms.
- exhaustiveness.test.ts: drop the matching case so the assertNever switch
  stays exhaustive (proven: re-adding the stale case makes tsc error TS2678).
- Read consumers App.tsx + Editor.tsx: re-point the closure checklist's
  trainingDelivered from the deleted handoff.signoff?.approvedBy to the handoff
  lifecycle (status === 'operational'); processOwnerAcknowledged already keys
  off status !== 'pending'.
- control.test.ts + controlActions.test.ts + both applyAction.control.test.ts:
  drop the signoff fixtures/assertions.

core tsc + both-app tsc clean. No IDB bump (non-indexed field removal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ame, PWA solo flow, decision-log §11 #6

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…atedAt (IM-7 review)

The team rail previously rendered the Signoff section whenever isCollaborative(ip)
was true. After a PWA local invite stamps collaboratedAt the section would appear
with a permanently-disabled "Request approval" button — the hidden-vs-disabled
anti-pattern (§9.2 / feedback_hidden_vs_disabled_cta).

New gating: isCollaborative(ip) && (!!onRequestSignoff || !!onApproveSignoff || !!onNudgeSignoff)
- PWA wires none of the three callbacks → section absent even post-invite
- Azure wires all three → section shows once collaborative (unchanged behaviour)

Also: update IPDetailTeamRail "approved state" test to wire onApproveSignoff (the
section now requires a callback to render), fix pwa-solo-investigation.md table and
sequence diagram note to reflect the accurate predicate, and add a new PWA test
asserting the section stays absent after collaboratedAt is stamped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ragments (IM-7 review)

- product-overview.md: drop "Charter ceremony" (Project created from Home + invite);
  reframe sign-off as optional/out-of-band; add to decision-log IM-7 apply-phase list
- ia-nav-model.md: "a Report the Sponsor signs off" → "Sponsor reviews (sign-off optional/out-of-band)"
- personas/lead.md: Mermaid "Sponsor reviews + signs off" → "Sponsor reviews (out-of-band sign-off; Lead records)"
- control.md: Mermaid node Rev[Sustainment review] → Rev[Control review] (code identifiers unchanged)
- applyAction.control.test.ts (azure + pwa): drop "signs off," from it() description
  (handoff signoff was deleted in IM-7; the test no longer exercises it)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e (IM-7 review)

The team rail gates sign-off on collaboratedAt AND >=1 sign-off callback;
the PWA wires none, so the section is always absent (even post-invite).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mean-beoynd-lite-pwa Ready Ready Preview, Comment May 30, 2026 2:39pm
variscout_website Ready Ready Preview, Comment May 30, 2026 2:39pm

@jukka-matti jukka-matti merged commit 8cd458c into main May 30, 2026
0 of 2 checks passed
@jukka-matti jukka-matti deleted the im-7-cluster-a-closure branch May 30, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant