Tools · LF cross-platform doc ← Tools menu → Open the board Updated 10-09-2026

Actions board · process doc

Documentation source-of-truth · same sections as the EO board doc (rule 15) · for AL and Claude

What this page is for. Fully documents how /lf-cross-platform-content (the byCaliber Actions board) works. Architecture, data model, the single view, synchronization rules, files involved, endpoints. Read by Claude at the start of any session that touches this page. Sections that exist on the EO board but not here say so, so the doc reads the same on the three intranets.

Table of contents

  1. A — Architecture (single root)
  2. B — Data model
  3. C — View 1 (Board)
  4. D — View 2 (Run)
  5. E — View 3 (Gantt)
  6. F — Synchronization
  7. G — Color code
  8. H — Context menus (right-click)
  9. I — Tracked runs (videos in production)
  10. J — Files, endpoints, D1 stores
  11. K — Deployment workflow
  12. L — Recent changelog

A — Architecture (single root)· non-negotiable principle

PHASES is the single root. The board content (phases, tasks, owner, app, link) lives in one constant inside the page script. D1 stores nothing but the ticks. render() derives everything shown from PHASES plus the tick map.

            ┌──────────────────────────────┐        ┌──────────────────────────┐
            │  PHASES (page constant)      │        │  D1 board_state          │
            │  phases[] · tasks[]          │        │  board_key = 'actions'   │
            │  id · name · owner · app     │        │  item_key = task id      │
            │  link · label                │        │  value_json = {done}     │
            └──────────────┬───────────────┘        └────────────┬─────────────┘
                           │ derives                             │ ticks
                           └────────────────┬────────────────────┘
                                            ▼
                                     ┌─────────────┐
                                     │  View 1     │
                                     │  Board      │
                                     └─────────────┘

D1 persistence: one row per item under board_key = 'actions' in board_state, written through /api/admin/board-state. Content changes (a new task, a renamed phase) are code changes deployed with the page; only ticks are data.

Golden sync rule. A tick goes to D1 first, the screen follows. No localStorage fallback: a tick that only lives in one browser is a lie. The server is authoritative on every reload and every tab focus.

B — Data model· JSON schema

B.1 PHASES (page constant)

[
  {
    num: '01', name: 'Find prospects', want: 'I want new names in the pipe.',
    tasks: [
      { id: 'find-01',              // D1 primary key, stable, never renamed without a migration
        name: 'Source new prospects',
        owner: 'Claude' | 'AL' | 'Robot',
        app: 'Notion',               // where the task happens
        link: 'https://…' | '/page', // what to open
        label: 'Prompt 01' },        // chip text
      …
    ]
  },
  …
]

Wired on byCaliber today: five phases, no task yet.

B.2 Tick (D1 table board_state)

{ board_key: 'actions', item_key: 'find-01', value_json: '{"done":true}', updated_at: 'YYYY-MM-DD HH:MM:SS' }

value_json is coerced server-side to { done: bool }: the endpoint rejects any other shape so the column never becomes a junk drawer.

B.3 Custom chain

None. Order on the board is the order of PHASES and of each tasks array. No arrows, no triggers.

B.4 Authoring conventions

C — View 1 (Board)· the only view

Purpose. See the whole pipeline in one column and tick items off. Structure edits happen in the page source, not in the UI.

C.1 Layout

C.2 Sub-actions

None. A task is the smallest unit.

C.3 Editor modal

None. Edit PHASES in public/lf-cross-platform-content.html and deploy.

C.4 Config buttons

One link chip per task (link + label). No PROMPT / URL / FINDER / OVERLAY families.

D — View 2 (Run)· not present

Not present on this board. The board is its own run view: the ticks are the run, there is no batch or wave projection.

E — View 3 (Gantt)· not present

Not present on this board. No cell chain, no arrows, no swimlanes.

F — Synchronization· reference contract

F.1 Storage

DataWhereWritten by
Phases, tasks, owners, apps, linksPHASES in the pageCode deploy
TicksD1 board_state, board actionsPOST /api/admin/board-state, one row per tick
In-flight writesinFlight map in memoryThe page, cleared when D1 answers

F.2 Visibility

Everything is on the one view. The status line (top right) shows done / total and the last sync word: saved, synced, or Not saved · reason in red.

F.3 Action → consequences

F.4 Positioning model

None. Order = source order.

F.5 Save guard

Per-item rows make the merge happen server-side: tab A ticking find-01 and tab B ticking close-02 touch different primary keys, both survive. No version token, no 409 needed.

F.6 Per-view memory

None (no localStorage by design).

G — Color code· owner + link

H — Context menus (right-click)· not present

None on this board.

I — Tracked runs (videos in production)· shared widget

/videos tracks runs in D1 video_runs (same API as EO: /api/admin/video-runs). On byCaliber no process board feeds the run steps yet (BOARD_SOURCES is empty in the page), so a run tracks its label, ISO week and A→Z duration and shows "No process board wired on this brand".

J — Files, endpoints, D1 stores· where to look

J.1 Source files

PathRole
public/lf-cross-platform-content.htmlThe board: HTML + CSS + JS inline, PHASES constant.
public/lf-cross-platform-content-doc.htmlThis doc.
public/videos.htmlTracked runs (EO template).

J.2 API endpoints

PathMethodsRole
/api/admin/board-stateGET ?board= / POSTRead all ticks of a board, upsert one tick. Coerces the value to {done}.
/api/admin/annotationsGET / POST / DELETESame table, board architecture_annotations, used by /architecture only (allowlist).
/api/admin/video-runs, /api/admin/video-runs/[id]GET / POST · GET / PATCH / DELETERuns list, create, detail, toggle, rename, archive, delete.

J.3 D1 stores

Key / TableSchemaCanonical source
board_state (board actions)1 row per ticked itemAPI /api/admin/board-state
board_state (board architecture_annotations)1 row per annotationAPI /api/admin/annotations
video_runs (dedicated table)1 row per runAPI /api/admin/video-runs

K — Deployment workflow· non-negotiable

No GitHub auto-deploy. On this repo (bycaliber-tools), git push ALONE deploys nothing. The prod page stays frozen on the last npm run deploy:prod.

cd ~/Projects/bycaliber-tools
# 1. Inline JS syntax validation (anti page-stuck-at-loading)
node -e "const fs=require('fs');const html=fs.readFileSync('public/lf-cross-platform-content.html','utf8');const scripts=[...html.matchAll(/<script>([\s\S]*?)<\/script>/g)];scripts.forEach((m,i)=>{try{new Function(m[1]);console.log('script',i,'OK')}catch(e){console.log('ERR:',e.message)}})"

# 2. DEPLOY (repo guard → mobile check → pages inventory → stamps → wrangler → smoke → auto-commit)
npm run deploy:prod

The deploy:prod script chains: scripts/repo-guard.sh → scripts/mobile-check.py → scripts/pages-inventory.js → scripts/stamp-pages.js → wrangler pages deploy public --project-name=bycaliber-tools --commit-dirty=true → scripts/smoke-test.sh → scripts/auto-commit-after-deploy.sh. D1 migrations are not part of the chain: apply 0004 / 0005 / 0006 by hand.

L — Recent changelog· updated at each iteration

2026-09-10 (rule 15 parity)