Skip to content

feat(members): chat-profile projection and escalation cards in the DM thread - #8614

Merged
iamwhatever merged 1 commit into
feat/escalation-user-peerfrom
feat/crew-chat-profile
Sep 7, 2026
Merged

feat(members): chat-profile projection and escalation cards in the DM thread#8614
iamwhatever merged 1 commit into
feat/escalation-user-peerfrom
feat/crew-chat-profile

Conversation

@CrysisDeu

@CrysisDeu CrysisDeu commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

The Crew Members DM thread rendered the member's raw transcript — every tool row, notice and nudge between the human's message and the member's reply. That is the right view on the Sessions page and the wrong one for a conversation. This PR gives ChatPane a displayProfile (transcript, the unchanged default, or chat) and mounts the chat profile on the Members page.

Crew chat demo — task, working state, escalation card with countdown and chips, one-click reply, view process, bell mirror

recorded from 693f9d3b5a327c73d4d9b698369cf4735f54166b · isolated pod wt-escalation, seeded config, crew "Radar" on the KAS backend · mode: --approval yolo · real server + real model turns, no fixtures

What the chat profile does

pages/members/chatProjection.ts is a pure projection over the same rows, computed client-side so the view can never disagree with the transcript it is drawn from:

  • Keeps the human's messages, the final assistant reply of each turn, escalation cards, approval and error rows. Hides tool / thinking / notice / nudge / inject / subagent rows and attaches them to the reply as meta.chat_process — one click on View process (N steps) shows them.
  • Working line. While the member runs a turn, "Working: ‹tool purpose›" stands in for the hidden rows (WS tool_call → slotStatusDetail; falls back to the tool name, then a generic line). It is the only busy indicator in the chat profile — the footer's ghost carousel is suppressed there (stopping/compacting states still show).
  • Silent rounds fold. Consecutive auto-nudge rounds whose reply said nothing new collapse into one "N check-ins with nothing new" row with its own expander. Implemented and unit-tested, but ships dark: a member thread cannot host an auto-nudge loop today (autonudge_authz refuses member-mode slots, and the member's kirocrew-core has no identity channel on KAS). Whether to lift that guard for member-armed loops is a separate decision.

Escalation cards

role: escalation rows (from #8613's session_escalate / POST /api/session-control/escalate) render as a card: title ("Radar needs you"), sender, goal chip, markdown body, a live countdown to the deadline, the default action if unanswered, and the options as a vertical single-choice list with one Send reply button (the same shape as QuestionCard; double-click an option to select and send in one gesture). The pick-then-send step is drawn, not implied: each option carries a radio dot, the button restates the pick once one is made (“Send ‘Hold until Monday’”, clipped to a phrase with the full text as its title), and until something is picked the hint beside it reads “Pick an option, then Send reply.” — so a click on an option is never mistaken for the reply. The reply carries meta.escalation_id, so the backend answers exactly that record — and because it is addressed by id, ChatPane.doSend does not treat it as the answer to whatever stateless question card or blocking ask happens to be pending on the slot (no capture, no retire): a reply to the member's escalation cannot silently dismiss an unrelated pending question. Card state is derived on the client by the same rule the index applies (#8613): a reply carrying the id answers that card; a free-text reply answers only when exactly one escalation is pending; a reply after the deadline never answers; the 1-second tick flips a live card to expired / defaulted ("Default applied: …") the moment the clock passes the deadline. The roster row shows a Needs you badge from the slot frame's needs_you. Every other surface keeps drawing #8613's read-only EscalationNotice (the SDK default), which points at the Members thread; this card is the ONE place an escalation is answered. The conversation index (GET /api/members/{slug}/conversation) is the authority on which escalation is still open; when that request fails before any record has loaded the cards fall back to the client-side rule, and when a REFETCH fails the last good record stays authoritative (a stale pending beats a window simulation that could read a truncated transcript as answered); either way an inline ErrorNotice under the thread says so (title + the raw error, no askAgent: the hand-off would unmount the pane and the composer draft in it), and the 20 s safety-net poll keeps retrying while a card is pending. An optimistic (not yet acknowledged) reply never counts as an answer, so a refused send leaves the card answerable. A reply the pane had to queue behind a running member turn keeps the card latched for as long as its queue entry exists; when the entry leaves the stack the latch lets go only if the server confirmed the cancel (useQueuedMessageActions now also exposes cancelledIds, the ids whose DELETE resolved) — the stack removes a cancelled entry optimistically, so an entry that is merely absent may still be queued behind a failed cancel and unlocking on absence alone would let a second reply run on top of the first. Unconfirmed, the authority (the index or the confirming row) is the only release. The same rule covers an uncertain acceptance — a 2xx the pane could not read, or one that arrived after the abort deadline (SendOutcome.uncertain): the reply may be queued under an id the host never learned, so the card drops its 45 s valve and waits for the authority instead of unlocking on a clock. One invariant, stated once: a reply the server may hold is never released by a timer or by an entry's absence — only by the index, the confirming row, or a server-confirmed cancel. Cancelling such a queued reply from the stack restores the pick on the card and nothing to the composer: the option send binds an empty pre-send record (queuedSendStash), so the cancel path takes the stash hit instead of parsing the row and appending the option label to the draft. For an option send only, that empty record is also registered under the send's own sendId (inFlightSendStash) BEFORE the request goes out and moved under the queue id when the receipt names one, so a cancel that lands in the queue_push-before-receipt gap still finds it by wire text — safe precisely because the record is empty by construction (typed sends, whose text and files could be mis-restored by a wire-text collision, stay bound by queue id only); and a server-confirmed cancel releases the card's latch even for an entry the stack never showed it, so that same gap cannot leave the card locked with no way out.

card answered

Coordination

MembersPage.tsx is touched in three small hunks only (isNeedsYou, the badge, the displayProfile prop) to stay clear of the in-flight remember-last-member and driving-sessions work in the same file. Everything else is new files under pages/members/ plus a displayProfile seam in ChatPane; messageRenderers.tsx is untouched (its escalation default stays #8613's notice).

i18n

26 keys under pages.members.chat in all 12 catalogs + regenerated pseudolocale, with per-language plural forms (CJK _other only; es/fr/pt/it _many; ru _few/_many); plural bases registered in pluralKeys.json; translator context in en.context.json. All 19 i18n:check gates pass against origin/main.

Tests

  • chatProjection.test.ts (11) — hiding, final-reply selection, process attachment, streaming kept while running, fold of 3 silent rounds, non-quiet round not folded, escalation/permission kept
  • EscalationCard.test.tsx (18) — body/options, select + Send → onSend(text, {escalation_id}), double-click quick send, radio dot + restated Send label + pick hint, long-option clipping, expired/defaulted (fake timers) closes the card and swaps the default line to "Default applied", live countdown and clock-crossing flip, answered badge, formatRemaining
  • chatProfileRenderers.test.tsx (6) — the assistant override wins after mergeRenderers, process disclosure, fold row, chips send via host handler, the SDK default alone draws feat(session-control): escalate to the human as a peer (session_escalate) #8613's EscalationNotice (not this card)
  • useEscalationIndex.test.tsx — fetch/poll/abort/dedupe, and error is set only by a FAILED request (null while loading, on success, and on a non-member slot)
  • MembersPage.test.tsx — badge from live slot and from roster fallback; ChatPane receives displayProfile="chat"
  • tsc -b, eslint, and the full i18n gate set are clean locally; the vitest suite for src/pages/members + src/i18n + the ChatPane working-loader harness passes (732 tests).

Stack

  1. fix(members): dispatch server carries the gateway home override #8611 fix/member-dispatch-home
  2. feat(members): thin per-member conversation index #8612 feat/crew-conversation-index
  3. feat(session-control): escalate to the human as a peer (session_escalate) #8613 feat/escalation-user-peer (base of this branch)
  4. this PR feat/crew-chat-profile

@CrysisDeu
CrysisDeu requested a review from a team as a code owner September 5, 2026 01:13
@CrysisDeu
CrysisDeu requested review from buluoray and removed request for a team September 5, 2026 01:13
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Sep 5, 2026
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — 🟡 CONCERNS

Design-level review of fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

temp-screenshots/ is a pre-existing repo convention (many subdirectories at base), so that's not a finding. I have what I need for the design review.

Design-Verdict: CONCERNS

Sound projection-over-transcript design; the one real risk is the escalation answer rule now living twice, client and server, pinned in sync only by prose.

Watch

  • escalationState.ts declares its simulation "mirrors the backend's exactly" and serves as the fallback whenever the index request fails or lacks the id — but nothing (shared fixtures, a contract test against feat(session-control): escalate to the human as a peer (session_escalate) #8613's index) pins the two implementations together. If the backend rule evolves (new provenance stamp, changed deadline semantics), the client fallback silently diverges and a card shows the wrong state precisely during the index outages the fallback exists for. Cross-pin the rule with a shared test vector set.
  • The silent-rounds fold "ships dark: a member thread cannot host an auto-nudge loop today" per the description — a reachable-by-nobody path in the projection contract that must be maintained until a separate guard-lift decision lands. If that decision goes the other way, it's pure carrying cost; consider deferring it to the PR that lifts autonudge_authz.

Suggestions

  • The queued-reply latch machinery (inFlightSendStash pre-registration, cancelledIds, the wire-text-gap rule) is a dense state machine embedded in ChatPane.doSend for one card type; extracting it into a named module with the "released only by the authority" invariant as its API would keep ChatPane from accreting per-profile races.

[DESIGN-REVIEWED] fe58d7a

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5) — 🟡 CONCERNS

UX-level review of fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Reconciliation is complete. The decisive fact: the committed screenshots and gif were captured from an earlier commit (693f9d3, per the PR body's own URLs) — shot-03 shows the hint "Or type a reply below.", a string that no longer exists at HEAD, and option rows without the radio dots the shipped card draws. The blind reader, reading that stale artifact, confidently misread the options as send-on-click ("answer buttons; clicking one sends that choice as my reply") — exactly the misread the shipped design (radio dot, "Pick an option, then Send reply.", restated "Send '…'" button) claims to fix, but that fix appears in no committed pixel and got no blind read. Everything else reconciled well: countdown, default line, Needs you badge, Hide process, Working…, and the answered-option bubble were all correctly identified.

UX-Verdict: CONCERNS

The shipped pick-then-send card is unphotographed: every screenshot shows the superseded chip design the blind reader misread as send-on-click.

Watch

  • The blind read confirms the risk the card was redesigned against — "answer buttons; clicking one sends that choice as my reply -> a confident one" (shot-03) — but the radio-dot/pick-hint/restated-button fix at HEAD has zero fresh evidence. High frequency (every escalation) × task impact (a pick-and-walk-away leaves the default to fire) × until re-verified. Fix: retake the screenshots at HEAD and re-run the blind read on them.
  • The same word "Working" now appears twice per viewport with different meanings — the new in-thread "Working…" line and the panel's orange "Working" status; the reader said "I can't tell if they are the same signal." Cheap fix: the purpose variant ("Working: ‹tool›") already disambiguates; make the generic line rarer or wordier ("Working on a reply…").

Evidence gaps

  • Card header (title "{{member}} needs you", state badge, goal chip, From line) is cropped out of both PNGs — retake escalation-card.png with the full card in frame.
  • Closed and feedback states in no screenshot: "Window closed — default applies" / "Default applied: …", "Withdrawn", "Reply sent", "Reply didn't send — try again.", and the index-failed notice.
  • crew-chat-demo.gif (the lens-13 recording) was too large for the blind reader to open and also predates HEAD — re-record from the current commit.

Suggestions

  • escalation_index_failed: "the member's escalation records" is vocabulary no surface shows the user (the card says "needs you") — reword to e.g. "Couldn't check whether this request is still open — retrying."

[UX-REVIEWED] fe58d7a

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — ✅ human override accepted

@CrysisDeu overrode this lane for fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1 via /ai-review override (this commit only).

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ human override accepted

Human judgment by @CrysisDeu overrides the GPT 5.6 finding for fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1; the recorded reason is authoritative for this commit.

This comment is updated in place on each push.

The model was not re-run because an authorized human decision supersedes it.

False positive or not applicable? A repository writer can comment:
/ai-review override gpt fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1: <one-sentence reason>

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Sep 5, 2026
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1 — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] fe58d7a

Verdict parsed from the review's SHA-scoped output markers for commit fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1.

False positive or not applicable? A repository writer can comment:
/ai-review override fable fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1: <one-sentence reason>

@CrysisDeu
CrysisDeu force-pushed the feat/escalation-user-peer branch from 916eda8 to 2e8d603 Compare September 5, 2026 01:51
@CrysisDeu
CrysisDeu force-pushed the feat/crew-chat-profile branch from ad706f1 to 2fdd676 Compare September 5, 2026 01:57
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: passed Eligible automated validation passed for the current revision and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 5, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/escalation-user-peer branch from 2e8d603 to 7e122ff Compare September 5, 2026 02:07
@CrysisDeu
CrysisDeu force-pushed the feat/crew-chat-profile branch from 2fdd676 to 256ccd7 Compare September 5, 2026 02:07
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: passed Eligible automated validation passed for the current revision readiness: checking Automated validation is still running labels Sep 5, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/escalation-user-peer branch from 7e122ff to c7e3957 Compare September 5, 2026 02:27
@github-actions github-actions Bot added the merge conflict Branch has merge conflicts with its base — author must resolve before merge label Sep 5, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/escalation-user-peer branch from c7e3957 to de85a4a Compare September 5, 2026 02:57
@CrysisDeu
CrysisDeu force-pushed the feat/crew-chat-profile branch from 256ccd7 to 9a55cdc Compare September 5, 2026 02:57
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Sep 5, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for 715d4f3529d3e5be8ab2e0708435b710bc7c4a0d.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles 52a2ade: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for 52a2adefcbe99b6fa306d1361e174b2d2b1f8e41.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles 36b1c16: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for 36b1c16db4ab96a1c7934dfa9cc51d8828cd9305.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

Two notes carried over from #8613's Design Review, for this PR's card (both are about copy/decisions, not #8613's backend):

  1. escalation_default_applied should not read as confirmation. The index state defaulted means "the veto window closed and a default had been declared" — the member that declared it is the one that runs it, and nothing in the backend confirms it ran (spec: "no deadline wakeup"). Copy along the lines of "Window closed — Radar said it would: X" states the fact; "the default is now in effect" over-claims. Same for the bell mirror if this PR mirrors state changes.

  2. Once chips are the primary answer path, should typed text still settle a record implicitly? feat(session-control): escalate to the human as a peer (session_escalate) #8613 keeps the free-text one-pending rule because typing is the only way to answer until this PR lands; the reviewer's point is that most of the reconciliation machinery exists to keep that rule faithful, and with chips it could become "chips answer; text is just text". That is a product call on the human's answer path — flagging it here so it is decided deliberately rather than inherited.

(#8613's head this note refers to: f0734a145c1483abedb14b30a536ab88c19cd7fe; it also adds meta.member on the escalation row, which this card can use for the actor's name.)

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles e2d57a9: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for e2d57a9aa0b549320fef158c05f9a45d4103525c.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles 67d8765: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for 67d8765ddb1d751b5adb2bd882391124db3c11d2.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles 436d6d4: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for 436d6d46ae128cab4caf2f7ea1ced1271996eb37.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

Follow-up from #8613 (head 516ed6a): the mark_answered docstring in crew_conversation.py says "the chat projection applies the same rule client-side" — that sentence describes THIS PR's card (settled state derived from later replies + deadline), not #8613's plain EscalationNotice. When this PR lands the card, please either make the sentence true or reword it to name the card explicitly.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles d068188: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for d068188b127e3d241570d3cb4623ad72d3abbeb3.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles cb05eab: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for cb05eab70cecabafa5da5514c083fb07c6693f2a.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles cd44572: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for cd4457271dd5852d434a3e72e08f0e65a2bdf73a.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles f838871: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for f8388717de9762fb5722252338d8d44c34731e84.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

… thread

The Crew Members DM thread rendered the member's raw transcript: every tool
row, notice and nudge between the human's message and the member's reply.
That is the right view on the Sessions page and the wrong one for a
conversation. This gives ChatPane a `displayProfile` — `transcript`
(default, unchanged) or `chat` — and mounts the chat profile on the Members
page.

The chat profile is a projection over the same rows (pages/members/
chatProjection.ts), computed client-side so the view can never disagree
with the transcript it is drawn from:

* human messages, the FINAL assistant reply of each turn, escalation cards,
  approval and error rows stay; tool / thinking / notice / nudge / inject /
  subagent rows are hidden and attached to the reply as `meta.chat_process`,
  reachable through a "View process (N steps)" expander;
* while the member runs a turn, a "Working: <tool purpose>" line stands in
  for the hidden rows (WS tool_call -> slotStatusDetail; falls back to the
  tool name, then a generic line);
* consecutive auto-nudge rounds whose reply said nothing new fold into one
  "N check-ins with nothing new" row with its own expander. (Implemented and
  unit-tested; a member thread cannot host an auto-nudge loop today because
  autonudge_authz refuses member-mode slots, so this ships dark until that
  guard is revisited.)

Escalation rows (role `escalation`, from session_send target=user) render
as a card: title, sender, goal chip, markdown body, a live countdown to the
deadline, the default action if unanswered, and option chips that send the
chosen text as the human's reply. Card state is derived on the client —
answered when a later user row exists, expired when the deadline passed —
so it needs no extra fetch. The roster row shows a "Needs you" badge from
the slot frame's `needs_you`. A read-only card variant is registered in the
SDK defaults and on the Sessions page so the row is never drawn raw.

MembersPage.tsx changes are three small hunks (isNeedsYou, the badge, the
displayProfile prop) to stay clear of the in-flight remember-last-member
and driving-sessions work in the same file.

i18n: 21 keys under pages.members.chat in all 12 catalogs + pseudolocale,
with per-language plural forms (CJK _other only; es/fr/pt/it _many; ru
_few/_many); bases registered in pluralKeys.json.

Evidence: temp-screenshots/crew-chat/ — GIF recorded on an isolated pod
against a real member session and real model turns, no fixtures.
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override first-principles fe58d7a: Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the first-principles AI finding as false positive, not applicable, or explicitly accepted for fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1.

Same finding as on 693f9d3, same ruling: the silent-rounds fold ships dark by design. Whether member slots may host auto-nudge loops is an owner-level product decision that lives in autonudge_authz.py, outside this PR; deleting a unit-tested, unreachable fold now only forces a delete-then-re-add across two reviews if the guard is lifted. The PR body says it ships dark. Tracked in #8908, which closes by either lifting the guard or removing the fold.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt fe58d7a: Cross-pane collision only appends a visible, deletable option label onto a preserved draft (not silent/irreversible loss), and needs a compound race of two panes sending the identical option with interleaved pre-receipt cancels.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the gpt AI finding as false positive, not applicable, or explicitly accepted for fe58d7ab10cbbfe32e78fdbf06ccbbcc978d8cf1.

Cross-pane collision only appends a visible, deletable option label onto a preserved draft (not silent/irreversible loss), and needs a compound race of two panes sending the identical option with interleaved pre-receipt cancels.

This decision applies only to this commit. A new push requires a new judgment.

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.

3 participants