Skip to content

Commit d2c23f2

Browse files
thewhycyborgclaude
andcommitted
XOS-146 — codi in-message status header: no-fabricate / no-silent-drop
New Stop hook status-liveness-check.ts verifies the model-authored Protocol 1 header against ~/.codialectic/state.json using the SAME freshness rule as statusline.sh (XOS-141) — one shared rule, so the in-message header and the terminal status line can never disagree. A score may appear only when codi is LIVE (fresh last_protocol_ts within the liveness window, version==installed_version, active); otherwise the header must be '⚠ Codi DEGRADED · [HH:MM]' with no numbers. Catches: fabrication (score-shaped token, with or without Cal:, while DEGRADED), inconsistent (rendered score != state last_score/last_cal), silent-drop (LIVE but no header), missing-degraded-header. Fail-open split: response unreadable → exit 0 silent; state.json missing/corrupt → treat as DEGRADED and still evaluate. Protocol 1 contract reworded in SKILL.md + SKILL-lite.md. Cross-family judge: GREEN (Gemini-Flash + Gemini-Pro tiebreaker; gpt-5.4 drove rounds 1-3 fixes). Version 4.27.0 across all 5 sources + root CHANGELOG. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 439b7b7 commit d2c23f2

11 files changed

Lines changed: 944 additions & 14 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
{
1212
"name": "co-dialectic",
1313
"source": "./plugins/co-dialectic",
14-
"description": "Co-Dialectic v4.23.0 - FORAGE: Epistemic Foraging flywheel. Weekly /forage tool-discovery loop: FORAGE (marketplace diff + GitHub trending + recommender + P20 web sweep) -> SCORE against the week's WORKSPACE session-ledger friction (not novelty) -> VERIFY in a throwaway worktree -> PROPOSE (install HUMAN-GATED, no auto-install; per-candidate approval ticket with evidence + rollback, max 3/run) -> CODIFY (pending/keepers/rejects/deferred + memory entry + audit ticket).",
15-
"version": "4.26.0",
14+
"description": "Co-Dialectic v4.27.0 - XOS-146 in-message status header liveness. status-liveness-check Stop hook verifies Protocol 1 headers every turn, blocks fabricated score prose via deterministic nudges, requires rendered score/Cal to match the fresh heartbeat in ~/.codialectic/state.json, and forces DEGRADED headers to omit all score numbers.",
15+
"version": "4.27.0",
1616
"category": "productivity"
1717
},
1818
{

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
All notable changes to this repository are tracked here. This project follows [Semantic Versioning](https://semver.org/).
77

88
---
9+
## [4.27.0] — 2026-06-29 — XOS-146: in-message status header liveness
10+
11+
Co-Dialectic now verifies the model-authored Protocol 1 header every turn. New Stop hook `hooks/status-liveness-check.ts` reads the final assistant message plus the same `~/.codialectic/state.json` liveness source and rule used by `statusline.sh` (one shared freshness rule, so the in-message header and the terminal status line can never disagree): a score may appear only when codi is LIVE (fresh `last_protocol_ts` within the liveness window, `version` == `installed_version`, `active` true). It recognizes only anchored Protocol 1 LIVE/DEGRADED header grammar (persona-led, optional `[HH:MM]`), nudges on fabricated score-shaped tokens — with or without `Cal:` — while DEGRADED, catches score/Cal mismatches against the heartbeat, reports silent drops of the required header, and distinguishes two error paths: a response that cannot be read → fail open silently (exit 0, no nudge); missing/corrupt `state.json` → treat as DEGRADED and STILL evaluate the rendered header. The Protocol 1 contract (SKILL.md + SKILL-lite.md) is reworded to match: when DEGRADED, render `⚠ Codi DEGRADED · [HH:MM]` with no percentages, never invented/recalled from prose.
12+
913
## [4.26.0] — 2026-06-29 — XOS-141: structural liveness (hook-rendered status + fail-LOUD + self-resurrect)
1014

1115
codi liveness made structural so the status line can never silently show a frozen/false-alive snapshot. `~/.codialectic/state.json` split into hook-owned fields (`installed_version`, `last_session_start_ts`, refreshed every SessionStart) vs model-owned (`last_protocol_ts`, score, persona — shown only when fresh). statusline.sh renders `⚠ Codi DEGRADED` on stale/version-skew/inactive instead of a frozen score. install-survival-layer.sh: create-if-missing → idempotent read-merge-write sync + corrupt-state fail-safe (backup before recreate, never silent-wipe of model fields). user-prompt-submit.ts deterministically detects degradation + injects a re-activation nudge (does not write last_protocol_ts). Protocol 1 writes the model-side heartbeat.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Codi in-message status header — no-fabricate / no-silent-drop
2+
3+
status: design
4+
slug: codi-status-no-fabricate
5+
ticket: XOS-146
6+
repo: ~/aiprojects/prompt-engineering-in-action (plugins/co-dialectic)
7+
8+
## What
9+
10+
Make codi's **in-message** status header (`{icon} {Persona} · X% · Cal: Y% · [HH:MM]`,
11+
Protocol 1) impossible to fabricate or silently drop. XOS-141 fixed the **terminal**
12+
statusLine (hook-owned, fail-loud); this fixes the **other** surface — the line the
13+
model types at the top of every response, which is currently model-authored prose with
14+
no grounded source.
15+
16+
## Why
17+
18+
2026-06-29, live proof: codi was dead the whole session (`~/.codialectic/state.json`
19+
frozen, `last_protocol_ts` null, cache stale), yet the model TYPED `91% · Cal 95%`
20+
headers with invented numbers, then silently dropped the header partway through, and
21+
mistook its own performance for codi running. The terminal statusLine being reliable
22+
does not help — the in-message header the user actually reads can still lie or vanish.
23+
Anchors: Zero-Hallucination (don't fabricate the score), verification-before-completion,
24+
[[feedback_dont_perform_a_dead_feature]].
25+
26+
## Scope
27+
28+
- **In:**
29+
- Contract rewrite in `SKILL.md` + `SKILL-lite.md` Protocol 1: a score `%`/`Cal:%`
30+
may appear ONLY when codi is live (a fresh `last_protocol_ts` heartbeat was written
31+
THIS turn AND the rendered numbers equal the `last_score`/`last_cal` just written).
32+
When DEGRADED (stale/absent `last_protocol_ts`, or `installed_version` skew) → header
33+
MUST read `⚠ Codi DEGRADED · [HH:MM]` with NO numbers. Never invent / recall a score
34+
from re-injected prose. `[HH:MM]` is always OS-grounded (Protocol 17).
35+
- NEW deterministic **Stop hook** `hooks/status-liveness-check.ts` (wired in
36+
`hooks.json`, following the existing `peer-parity-nudge.ts` Stop-hook pattern):
37+
reads the model's final assistant message + `state.json`, computes liveness, and
38+
emits a LOUD deterministic nudge on any of the three failure modes (below). This is
39+
the codification — replaces "the agent notices the drop" with a hook that always
40+
checks. Reuses the SAME freshness rule as `statusline.sh` (XOS-141) so the two
41+
surfaces can never disagree (extract/share the freshness predicate; if bash↔TS
42+
sharing is impractical, replicate the exact same threshold + skew rule and assert
43+
it in a test).
44+
- Tighten the `user-prompt-submit.ts` survival reminder text to state the contract
45+
explicitly ("a score requires a fresh heartbeat you write THIS turn; else
46+
`⚠ Codi DEGRADED`, never a %").
47+
- Version bump 4.27.0 across all 4 sources + root CHANGELOG + SKILL-lite.
48+
- **Out:**
49+
- Deprecating the in-message header entirely in favor of the terminal statusLine
50+
(ticket direction 4) — bigger UX call; the contract + Stop hook make the in-message
51+
surface trustworthy without removing it. Noted as a future option, not this ticket.
52+
- Any change to the XOS-141 `statusline.sh` behavior (only share its freshness rule).
53+
- Any phone-home / telemetry. Local-only, as always.
54+
55+
## Acceptance criteria
56+
57+
- [ ] In-message header shows `X%`/`Cal: Y%` ONLY when `last_protocol_ts` is fresh AND
58+
the rendered numbers equal `state.json` `last_score`/`last_cal`.
59+
- [ ] When codi is DEGRADED (stale/absent `last_protocol_ts` or version skew), the
60+
correct header is `⚠ Codi DEGRADED · [HH:MM]` with no numbers — documented in
61+
Protocol 1 (SKILL.md + SKILL-lite.md).
62+
- [ ] `hooks/status-liveness-check.ts` (Stop hook) deterministically emits a loud nudge on:
63+
(a) **fabrication** — a numeric score present in the response but state NOT fresh;
64+
(b) **inconsistent** — rendered number ≠ `state.json` `last_score`/`last_cal`;
65+
(c) **silent drop** — state IS fresh but the response has no status line.
66+
No nudge when the DEGRADED header is correct, or when fresh + numbers match.
67+
- [ ] The Stop hook fails safe: missing/corrupt `state.json` → treat as DEGRADED
68+
(expect DEGRADED header), never crash.
69+
- [ ] Freshness predicate matches `statusline.sh` (XOS-141); a test asserts they agree.
70+
- [ ] Version 4.27.0 in: `.claude-plugin/marketplace.json`, `plugins/co-dialectic/.claude-plugin/plugin.json`,
71+
`plugins/co-dialectic/skills/co-dialectic/SKILL.md` `**Version:**`, `install.sh` `VERSION=`,
72+
and `SKILL-lite.md` `**Version:**`; root `CHANGELOG.md` `## [4.27.0]` entry.
73+
- [ ] `test-plugin.sh` validate green; `gh pr checks` green.
74+
75+
## Test plan
76+
77+
- [ ] `bun test` unit tests for `status-liveness-check.ts` covering the 4 cases
78+
(fresh+match → no nudge; stale+number → fabrication nudge; mismatch → inconsistent
79+
nudge; fresh+no-line → silent-drop nudge) + fail-safe on missing state.json.
80+
- [ ] Freshness-parity test: same (last_protocol_ts, now, installed_version) inputs →
81+
same live/degraded verdict as the statusline.sh rule.
82+
- [ ] CLI render smoke (Stage 5.5 plugin/CLI mode): hooks load + run without stack traces
83+
at narrow + standard widths; the new hook handles absent state.json gracefully.
84+
85+
## Rollback
86+
87+
Revert the PR; remove the `status-liveness-check` entry from `hooks.json`. Additive hook
88+
+ doc edits in one plugin; no data migration; low blast radius. The terminal statusLine
89+
(XOS-141) is unaffected, so liveness signalling never regresses below today.

install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
set -e
77

88
REPO="https://raw.githubusercontent.com/Exponential-OS/prompt-engineering-in-action/main"
9-
VERSION="4.26.0"
9+
VERSION="4.27.0"
1010
CONFIG_DIR="$HOME/.co-dialectic"
1111
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" 2>/dev/null && pwd || pwd)"
1212
TARGET_ARG="auto"

plugins/co-dialectic/.claude-plugin/plugin.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "co-dialectic",
3-
"description": "Co-Dialectic v4.26.0 - XOS-141 structural liveness. statusLine gates model-owned score fields behind a fresh Protocol 1 heartbeat, hook-owned installed_version/session-start fields refresh every SessionStart, stale/skew/inactive state fails loud as DEGRADED, and UserPromptSubmit injects a deterministic Protocol 0/1 self-resurrection nudge without faking last_protocol_ts.",
4-
"version": "4.26.0",
3+
"description": "Co-Dialectic v4.27.0 - XOS-146 in-message status header liveness. status-liveness-check Stop hook verifies Protocol 1 headers every turn, blocks fabricated score prose via deterministic nudges, requires rendered score/Cal to match the fresh heartbeat in ~/.codialectic/state.json, and forces DEGRADED headers to omit all score numbers.",
4+
"version": "4.27.0",
55
"depends_on_kernel": [
66
"brain-kernel >= 1.0.0",
77
"co-dialectic >= 4.16.0"

plugins/co-dialectic/hooks/hooks.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"description": "Co-Dialectic hooks — persistent survival + dev-cycle visibility + foundation invariant harnesses + auto-handoff before compaction. SessionStart auto-installs survival layer. UserPromptSubmit re-injects codi context + OS-grounded datetime (temporal-grounding harness). PreToolUse(Skill) emits plugin+version+scope banner. PreToolUse(Edit/Write/MultiEdit) fires the codify-or-mark-uncodified scan on .md files in invariant-carrier locations. Stop hook fires the unit-of-work-commit reminder when workspace cwd has uncommitted changes. PreCompact hook (v4.21.0+) auto-triggers the codi-handoff skill before context summarization. TaskCompleted hook (v4.22.0+) runs the cross-family judge-panel cascade on agent-team task completions — opt-in via CODI_TEAM_JUDGE_GATE=1; exit 2 blocks completion and feeds jurors' flags back to the teammate.",
2+
"description": "Co-Dialectic hooks — persistent survival + dev-cycle visibility + foundation invariant harnesses + auto-handoff before compaction. SessionStart auto-installs survival layer. UserPromptSubmit re-injects codi context + OS-grounded datetime (temporal-grounding harness). PreToolUse(Skill) emits plugin+version+scope banner. PreToolUse(Edit/Write/MultiEdit) fires the codify-or-mark-uncodified scan on .md files in invariant-carrier locations. Stop hooks verify the in-message status header liveness and fire the unit-of-work-commit reminder when workspace cwd has uncommitted changes. PreCompact hook (v4.21.0+) auto-triggers the codi-handoff skill before context summarization. TaskCompleted hook (v4.22.0+) runs the cross-family judge-panel cascade on agent-team task completions — opt-in via CODI_TEAM_JUDGE_GATE=1; exit 2 blocks completion and feeds jurors' flags back to the teammate.",
33
"hooks": {
44
"SessionStart": [
55
{
@@ -53,6 +53,11 @@
5353
"Stop": [
5454
{
5555
"hooks": [
56+
{
57+
"type": "command",
58+
"command": "/Users/anandvallam/.bun/bin/bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/status-liveness-check.ts\"",
59+
"timeout": 3000
60+
},
5661
{
5762
"type": "command",
5863
"command": "/Users/anandvallam/.bun/bin/bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/unit-of-work-check.ts\"",

0 commit comments

Comments
 (0)