Skip to content

Workbook v0.5.0

Choose a tag to compare

@github-actions github-actions released this 18 Aug 21:33
· 53 commits to main since this release
e6fdd49

A project now owns its statuses, tasks carry comments, attachments and
assignments, deleted tasks come back through the board, and project identity
no longer depends on what a branch happens to contain — from thirty reviewed
pull requests.

Project identity

  • Project identity moves out of branch content into refs/workbook/project.
    A checkout taken before a project adopted Workbook carried no
    .workbook/config.json, so bootstrap minted a second identity and the
    private guard then rejected the real configuration on every command; refs
    live in the common Git directory, so nothing about a branch can strand
    identity anymore. The ref is written deterministically, so two clones
    adopting the same project converge on the same commit, and a disagreeing
    private guard is now repaired from the ref instead of wedging the
    repository (#81).

Per-project statuses

  • The status vocabulary becomes a modeled document, and status validity moves
    to the mutation boundary. A status stored in history is never rewritten,
    only resolved through the vocabulary on read — so every task ref already
    written stays byte-identical, a property captured in a golden test against
    the previous release before any change landed (#82).
  • The vocabulary lives in refs/workbook/config, a configuration ledger with
    a Git history of its own, synchronized and reconciled the way task refs
    are: a rename made in one clone arrives in the next as an operation, not a
    file merge, so concurrent changes converge or surface as domain conflicts
    instead of conflicting a JSON file (#83).
  • workbook status gives a person and an agent the vocabulary: list,
    add, rename, label, move, tag, untag, delete --into, and
    log, whose every entry prints the exact inverse command that would undo
    it. Deleting a status requires a destination, so no task is ever stranded
    by a vocabulary change (#84).
  • Both boards build their columns from the project's own vocabulary. A
    project that renamed ready to todo used to get a READY column with the
    task missing from it; a stored status that a rename or removal forwards is
    now drawn in the column it now means, and only a status that forwards
    nowhere lands in the unknown region. The terminal's wide-layout threshold
    becomes a per-column budget, so a three-status project reaches its wide
    layout on a terminal that could never have fitted six (#85).
  • The generated guidelines describe the statuses the project actually has:
    the table gains position and tag columns with a legend saying what each tag
    makes the machine do, and the lifecycle prose is read off the tags rather
    than off hardcoded names (#86). A display label carrying an HTML comment
    opener can no longer swallow the rest of the generated document, and the
    migration note about a retired default column stops nagging a project that
    deliberately added the column back (#90).
  • A new project no longer gets a Blocked column. Tasks have dependencies, and
    a column duplicating that claim is a second answer to the same question.
    Nothing is taken from existing projects: a project that already has
    blocked keeps it until a person runs
    workbook status delete blocked --into <status> — this repository ran
    exactly that migration (#87, #88).
  • The statuses can be administered from the browser at /statuses: add,
    rename, relabel, retag, reorder by drag or by buttons, and delete into a
    chosen destination, with each change reporting how many tasks moved and how
    many became claimable. Every mutation names the columns the caller actually
    saw and is refused as stale rather than merged when they have changed; the
    board's columns are never rebuilt live under a reader — a standing notice
    offers the reload. The first cut opened as a half-height sliver over the
    board and became a page of its own before release (#92, #93, #94). The
    reorder answers a drag on dragenter as well as dragover, so a browser
    engine that switches events when content moves under the cursor still finds
    a panel that answers, and the drop mark survives the leave-event churn a
    cursor crossing child elements produces (#110).
  • A task stranded on a status that resolves nowhere can be dragged back onto
    the board: the web unknown-status region's cards are draggable out into any
    column, status list bounds its unresolved listing to the first ten IDs
    while keeping the count exact, and the contract is written down — an
    unrecognized status is a mutation refusal, never a corruption claim (#89).
  • The web board's columns were sized by a hardcoded six-track grid, so a
    five-column board sat frozen at minimum width until the viewport reached
    about 1640px while a phantom sixth track absorbed the free space. The board
    now creates exactly one track per rendered column, growth begins as soon as
    the columns can use the space, and columns stop growing at 26rem so a wide
    monitor no longer stretches every card across the page (#91).

Deleted tasks

  • Deleted tasks are a hideable "Deleted" column at the end of the board
    instead of a separate page. The header link toggles /?deleted=1, so the
    state is bookmarkable and Back works; the column lists tombstones
    newest-first with a Restore button on each card, and dragging works both
    ways — a deleted card dropped on a status column is a restore naming its
    destination and position, and a live card dropped on the Deleted column is
    a delete. The /deleted page is gone (#96).
  • workbook restore gained --into <status>, so a deleted task can come
    back into a chosen column instead of the one it died holding, recorded as
    one history entry; the web restore accepts the same choice (#95).

Comments, attachments and assignments

  • Tasks carry a comment thread and an attachment list — comments that can be
    added, edited and removed, attachments that are an uploaded file's bytes or
    a link. Concurrent edits converge, and a task with neither stores exactly
    the bytes it always did. Ceilings are asked as growth — 16 KiB per comment,
    500 comments, 50 attachments, 1 MiB per file, 10 MiB of live files per
    task — so a task carried over a limit by a teammate's change can still be
    edited and, above all, shrunk back under it (#99).
  • workbook update composes them into single commits: --comment,
    --edit-comment, --remove-comment, --attach-file, --attach-url with
    --attach-label, and --remove-attachment, alongside --status and the
    rest; workbook show prints the thread and the list, and
    show --get-attachment writes a file's bytes out. Comment and attachment
    IDs take any unambiguous prefix, the same contract task IDs have (#100).
  • Tasks can be assigned. An assignment names a principal with an optional
    agent label and records who assigned it and when; two clones assigning the
    same task both survive as a legible both-assigned state, and an assignment
    can only be removed by the person it names or whoever recorded it — a
    removal by anyone else is recorded and changes nothing, on every clone
    (#98). --assign self claims in one atomic commit with a status change,
    workbook next skips tasks held only by others and says so when everything
    eligible is held, next --claim picks and assigns in one step, and
    assigning over somebody else's hold is refused — exit 10, naming the holder
    and --force, which records the assignment beside theirs (#101).
  • The web task page gained the comment thread and the attachment list —
    add, edit, remove, upload, link, download. These panels are deliberately
    not optimistic: identity and attribution come from the recorded operation,
    so each panel disables, sends, and draws the answer. Only GIF, JPEG, PNG
    and WebP are served inline; every other type, including every spelling of
    SVG, downloads as an opaque attachment (#102). The board and task page also
    show who holds a task — assignee chips on held cards, an Assignments
    section on the task page — derived through the same functions the terminal
    prints, so the surfaces cannot drift (#104).
  • The New Task form stages attachments before the task exists. Files and
    links are checked against the same ceilings the server enforces before
    anything uploads; a create whose attachments partially fail holds the form
    with per-row reasons and a Retry attachments button bound to the task it
    created, and the panel refuses changes while a run is walking it (#106).
  • Both attachment surfaces accept drag and drop, through the same pre-checks
    as picked files. A refused file says why while the drag is still over the
    zone — a refused drop is cancelled by the browser and never delivered, so
    the drop handler was never the place to say it; a dropped folder is named
    rather than staged and failed; and a file dropped near the board can no
    longer move an unrelated card, nor navigate the page away and destroy
    staged work (#109).

Markdown

  • Task descriptions and comment bodies render as markdown in the browser:
    headings, emphasis, code, lists, blockquotes, http and https links, and
    images. The description opens rendered with an Edit control that swaps the
    textarea in. Images are written ![alt](attachment:<id>) and resolve only
    against the task's own attachments — every other image target, including
    external URLs, is drawn as text, so a board never reports its readers to
    whoever wrote a task. Anything outside the subset is drawn as the
    characters that were typed (#103).

Web board drag and scroll

  • A board column taller than its viewport could only be reordered a few
    places per gesture. A column now scrolls while a card is held near its
    edge, ramping with depth, and keeps scrolling at full speed when the card
    is pushed past its end; the drop line is recomputed as the cards move, so
    the card lands where the line shows. This round also fixed drops being
    silently lost after a column had autoscrolled — the browser stops sending
    dragover when content churns under a still cursor, which cancelled the
    drop entirely (#105).
  • A card dragged toward a column off the side of the window carries the
    board with it, both axes at once from one held cursor, with the edge zones
    measured from the window the reader can actually reach — which matters
    under large default fonts and narrow windows, where the document itself
    scrolls sideways (#108).
  • The board's header holds its shape: Board and Statuses sit by the heading
    as links, the display controls are labeled toggle switches with pinned
    widths, and the updated-time no longer shoves them around as it changes
    (#107).

Compatibility across versions

  • History written by a newer Workbook is refused with an upgrade signal
    instead of a corruption claim. Reads still serve the task from its stored
    checkpoint with an advisory, mutations of that one task are refused with
    the new newer-writer category and exit 9 saying to upgrade, and fetch,
    sync and push keep working — nothing wedges, other tasks are unaffected,
    and unpublished local work publishes itself on the first sync after
    upgrading (#97). Assignments, comments and attachments are the first
    writers to raise the format generation, so this boundary is now guarded in
    both directions going forward. A clone still on v0.4.4 predates the signal
    and reports a task carrying them as corrupt-data — which an upgrade, not a
    repair, resolves; tasks without them stay byte-identical everywhere.