Skip to content

Status entry and pipeline band showing the work state #203

Closed

Description

@ToRvaLDz

Parent: 🗺 trailhead mod

Question

Show the work state on screen: a status entry ($.ui.status: map, ticket number and title, step) and a band above the prompt drawing the pipeline discuss -> plan -> execute -> verify with the current step highlighted (and, during an autonomous run, a tickets-done counter). Both read the work state as decided, redraw when it changes, stay quiet when no ticket is in play, and render on the terminal and desktop surfaces (tests loop over both).

Blocked by

Activity

  1. self-assigned this
    on Oct 10, 2026
  2. ToRvaLDz commented on Oct 11, 2026

    @ToRvaLDz
    OwnerAuthor

    PLAN

    Closed at the brief: the autonomous-run counter is added to the work state helper in this ticket (new field autoDone), not deferred to the auto loop ticket.

    Steps

    1. Helper: autoDone field (plugins/trailhead/templates/trailhead-work-state.js). New flag --auto-done <n> (non-negative integer, strict parse, usage error otherwise). Shape becomes { map, ticket, title, step, auto, autoDone, session, updatedAt }; autoDone defaults to 0, is kept by a merge like the other fields, is dropped by a ticket change unless passed again, and is reset to 0 whenever the merged auto is false. sanitizeState accepts a non-negative integer only. TDD: extend hooks/lib/work-state.test.js first (parse, merge, reset on auto false, invalid value rejected, old file without the field).
    2. Skill prose: _shared/teamwork.md Work state paragraph and trailhead-work/references/auto.md say that during an autonomous run every set adds --auto true --auto-done <n>, n the tickets resolved so far in this run. Codex projection test pins the new form (bin/lib/codex-projection.test.js).
    3. Contract (plugins/trailhead/types/index.d.ts): WorkState gains autoDone: number; PluginState.trailhead gains isOrphaned: boolean.
    4. Pure view logic (plugins/trailhead/hooks/mod/work-state-view.ts, new): parseWorkState(text) validates the file the same way the helper does (bad JSON or no valid ticket/step -> null, missing autoDone -> 0); statusLine(state, isOrphaned) -> trailhead map #198 · #203 Title · plan (whiteboard in place of map #<n> when map is null; · auto 3 done appended during a run; the same line with · orphaned, resume? appended when orphaned (map, ticket, title and step kept); undefined when no state); pipeline(step) -> the four stages with done | current | todo (resolve = all done, paused = the stage is unknown, shown as a paused tag).
    5. Mod wiring (plugins/trailhead/hooks/mod/register.ts): refresh($) reads .trailhead/work-state.json via $.fs.read (relative to the session cwd) and compares session with $.session.id() to set isOrphaned (a null session in the file is not orphaned). Outcomes: a missing file (rejection carrying ENOENT) or an unparseable one -> both atoms reset to null/false, $.ui.status(undefined), band gone; any other read error (transient) -> keep the last state untouched. Atoms are written only when the value changed, compared structurally on the normalised state (key-ordered JSON), never by reference (no redundant redraw), and the status is set only when its text changed. On session.end with reason: 'clear' (a /clear changes the session id and raises no session.start) a state still on screen is marked orphaned at once, since the session that wrote it is gone. Refresh is called on session.start, turn.start (re-checks against the new session id after a /clear), turn.complete, and on a Bash tool.call whose command names trailhead-work-state.js, after await next(e) so the helper has already written (the helper is the only writer, so this catches every step change mid-turn). Every hook passes through next(e); a refresh failure never blocks (caught, logged to debug).
    6. Band (ui.render on AbovePrompt): reads both atoms reactively with read($, atom) (so a write redraws the band, no manual invalidate); next(e) when there is no state or a survey holds the band (e.props.hasSurvey); otherwise one row #203 Title (truncated to bodyColumns) and one row discuss › plan › execute › verify, the current stage bold in the accent colour, done stages plain, pending ones dim, plus auto · 3 done during a run; the whole band dim with an orphaned, resume? tag when orphaned. Only elements both terminal and desktop tables carry (Box, Text).
    7. Tests (plugins/trailhead/tests/work-state-ui.test.ts, new), each looped over ['terminal', 'desktop']: the test's on answers fs.read and session.id and records ui.status; cases: no file (band draws nothing, status cleared); a valid file then the file removed (band and status cleared); a non-ENOENT read error keeps the last state; status text with a map and with map: null; each step highlights the right stage, resolve and paused; auto counter shown; orphaned dims and changes the status text; hasSurvey yields; a Bash tool.call naming the helper re-reads only after its next resolved (the test's tool.call answer writes the new file content) and redraws; an unchanged file produces no extra ui.status call and no redraw (render count unchanged); session.end with reason: 'clear' marks a shown state orphaned without a new turn. Existing mod.test.ts kept.
    8. Docs: hooks/mod/README.md drops "nothing visible yet" and describes the status and band. READMEs and /docs are left to the map's release ticket (fog 13), as with Scaffold the mod in the plugin with its dev and test loop #202.

    Seams (TDD per tdd: seams)

    • helper mergeState / parseArgs (node unit tests, red first);
    • parseWorkState / statusLine / pipeline and the AbovePrompt render (mod tests, red first).

    Files touched

    plugins/trailhead/templates/trailhead-work-state.js, plugins/trailhead/hooks/lib/work-state.test.js, plugins/trailhead/skills/_shared/teamwork.md, plugins/trailhead/skills/trailhead-work/references/auto.md, bin/lib/codex-projection.test.js, plugins/trailhead/types/index.d.ts, plugins/trailhead/hooks/mod/register.ts, plugins/trailhead/hooks/mod/work-state-view.ts (new), plugins/trailhead/tests/work-state-ui.test.ts (new), plugins/trailhead/hooks/mod/README.md.

    Verification criteria

    • npm test green (all node suites, claude plugin validate, claude plugin test).
    • Band and status render on both surfaces in the tests; quiet with no file.
    • A live claude --plugin-dir plugins/trailhead session in this repo shows the status and band for the ticket in play and redraws on a step change.
    • Codex install unchanged apart from the projected prose (projection tests green).
  3. ToRvaLDz commented on Oct 11, 2026

    @ToRvaLDz
    OwnerAuthor

    PLAN-REVIEW

    Reviewer: codex (2 rounds, read-only). All blocking concerns folded into the PLAN above.

    Round 1

    • BLOCKING: status line omitted the map. Fixed: map #<n> (or whiteboard) in the line, tested with and without a map.
    • BLOCKING: a missing file vs a failed read was ambiguous. Fixed: ENOENT or an unparseable file clears both atoms, the status and the band; any other read error keeps the last state.
    • BLOCKING: redraw not guaranteed. Fixed: the band reads the atoms reactively with read($, atom).
    • BLOCKING: the tool.call refresh must follow the helper's run. Fixed: refresh after await next(e), tested.
    • NON-BLOCKING: /clear emits no session.start. Fixed: refresh on turn.start too.
    • NON-BLOCKING: missing tests (map format, file removed, hasSurvey, no redundant writes). Added to step 7.

    Round 2

    • BLOCKING: /clear still not handled at once. Fixed: session.end with reason: 'clear' marks a shown state orphaned immediately, tested.
    • BLOCKING: the orphaned status dropped map, title and step. Fixed: the full line is kept with · orphaned, resume? appended (mockup updated to match).
    • NON-BLOCKING: "write only when changed" needs a structural comparator. Fixed: key-ordered JSON comparison, pinned by a no-redraw assertion.

    The rounds are spent; the round 2 fixes are targeted and were not re-reviewed.

  4. ToRvaLDz commented on Oct 11, 2026

    @ToRvaLDz
    OwnerAuthor

    Mockup approved (explicit approval by the maintainer).

    Canvas: https://claude.ai/artifact/JJYUnUqxymHmPMpbXx1n2e, page "Status entry and pipeline band (#203)", artboard "Work state band and status" (version 1791708479-d928). Re-fetched after approval, unchanged.

    States: ticket in play, autonomous run with counter, paused, orphaned (after /clear), resolve, no ticket in play. Band: row 1 #<n> (bold accent) + title cut to the band width, [-] belongs to the engine; row 2 the four stages, done ✓ green, current ▸ bold accent, pending dim, ‖ paused or orphaned, resume? tag in amber, auto · <n> done right-aligned in amber. Status entry: trailhead map #<m> · #<n> <title> · <step>[ · auto <k> done][ · orphaned, resume?].

  5. ToRvaLDz commented on Oct 11, 2026

    @ToRvaLDz
    OwnerAuthor

    Mockup fidelity (approved artboard "Work state band and status"), each test run on terminal and desktop:

    Mockup element / state Reproduced Proven by
    1 Ticket in play: ✓ done green, ▸ current bold accent, pending dim, dim › yes work-state-ui.test.ts "each step highlights its stage"
    2 Auto run: auto · <n> done amber, right-aligned on row 2 yes (space-between row at bodyColumns; props checked, not paint) auto counter test
    3 Paused: names dim, ‖ paused amber yes step test (paused)
    4 Orphaned after /clear: band dim, no bold, orphaned, resume? amber yes orphaned test + "/clear marks a shown state orphaned"
    5 Resolve: all four ✓ green yes step test (resolve)
    6 No ticket in play: nothing drawn, no status yes "no state file", file-removed tests
    Row 1: #<n> bold #7aa2f7 + title cut with … to bodyColumns; engine's [-] not drawn yes truncation test at width 40
    Status entry trailhead map #<m> · #<n> <title> · <step>[ · auto <k> done][ · orphaned, resume?], whiteboard variant yes status line tests

    Deviations decided in Execute (none visible in the mockup): when a state is both paused and orphaned, only the orphaned tag shows; when orphaned, the auto · <n> done text is hidden from the band (still in the status line).

  6. ToRvaLDz commented on Oct 11, 2026

    @ToRvaLDz
    OwnerAuthor

    VERIFY

    Tests: node scripts/test.js 23 ok/skipped, 0 failed (node suites, claude plugin validate, claude plugin test: 32 mod tests on terminal and desktop).

    Code review (2 rounds, ticket diff = the Refs: #203 commits 0ca9566, 96b8257, 85bf404, 7b17720, 8b5c2b4, fc13de6, 7192c93): status: clean.
    critical: 0 · warning: 0 · info: 1

    Findings ledger

    • I1 (info): the band title cut counted UTF-16 units and could split an emoji's surrogate pair: fixed (fc13de6, code-point cut + test).

    Goal-backward verification: status: met (14 claims met, mockup fidelity included). Its one note, /clear marking a work state with no session as orphaned, contradicting the "no session is never orphaned" rule: fixed (7192c93, + test).

    Acceptance testing: guided live session (claude --plugin-dir plugins/trailhead), driven by the maintainer, in progress.

  7. ToRvaLDz commented on Oct 11, 2026

    @ToRvaLDz
    OwnerAuthor

    VERIFY (acceptance): guided live check, driven by the maintainer in claude --plugin-dir plugins/trailhead (Claude Code 2.1.296, terminal). Pass.

    1. A work state written by another session: band dim with orphaned, resume? in amber, status entry with the orphaned suffix. Pass.
    2. set --step execute from the test session: redraw right after the Bash call, no longer orphaned, ▸ execute in accent, verify dim. Pass.
    3. --auto true --auto-done 3: auto · 3 done right-aligned in amber on row 2, auto 3 done in the status entry. Pass.
    4. clear: band and status entry gone. Pass.

    Found during the check: the engine prefixes a plugin's status with ⚠ trailhead: in its own warning colour, so the entry read trailhead: trailhead map .... With the maintainer's agreement the entry's own prefix was dropped (ce8ba9f, tests updated) and the mockup updated to match (version 1791709261-979c). The glyph and colour are the engine's and cannot be changed by the mod.

  8. ToRvaLDz commented on Oct 11, 2026

    @ToRvaLDz
    OwnerAuthor

    Resolved. The mod now shows the work state on screen.

    • Status entry ($.ui.status): map #198 · #203 <title> · <step>, with whiteboard for a map-less ticket, · auto <n> done during an autonomous run, · orphaned, resume? when the file belongs to another session; the engine prefixes it with ⚠ trailhead: (7b17720, ce8ba9f).
    • Band (AbovePrompt): #<n> + title cut to the band width, then discuss › plan › execute › verify with done ✓, current ▸ in accent, pending dim; ‖ paused, orphaned, resume? and the right-aligned auto · <n> done in amber; dims when orphaned, yields to a survey, draws nothing with no ticket in play (7b17720, fc13de6, 7192c93).
    • Refresh: reads .trailhead/work-state.json on session.start, turn.start, turn.complete and after a Bash call to the helper; a missing or unparseable file clears both, a transient read error keeps the last state; writes only on a real change; /clear marks a state with a session orphaned at once (7b17720, 7192c93).
    • Helper: new autoDone counter (--auto-done <n>, reset when auto is false), passed by the autonomous run; Codex projection pinned (0ca9566, 96b8257).
    • Pure view logic in hooks/mod/work-state-view.ts, contract autoDone + isOrphaned, module renamed register.tsx (85bf404, 7b17720); mod README updated (8b5c2b4).

    Verification: VERIFY (review ledger clean, goal met) and acceptance (live check passed). Mockup: canvas page "Status entry and pipeline band (#203)".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

trailhead:buildtype: construct — discuss/plan/execute/verifytrailhead:map-198Tickets of map #198 (trailhead mod)trailhead:ticketa trailhead ticket

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions