Cards#snapshot again emits all 19 Types::Card fields (camelCase) plus
labels — 8df0cb7 had narrowed it to 8 keys, dropping listChangedAt and
silently breaking board-audit's stale-Doing check. A regression test
now pins the complete key set (35 runs green). implementation-status
records the 0.2.0 typed-returns migration and the live end-to-end
verification against the real Planka board (run on ovh-vps 2026-07-10).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BS59Nkb7fvJMFB9dZiwZ7H
This commit is contained in:
parent
8df0cb7e1e
commit
bfb747bd7e
|
|
@ -137,6 +137,36 @@ behind gem issue 13) and live verification completed against production Planka
|
||||||
Backlog card: get planka_bot into credvault (credvault has no import path — rotate vs.
|
Backlog card: get planka_bot into credvault (credvault has no import path — rotate vs.
|
||||||
add import capability is a human decision).
|
add import capability is a human decision).
|
||||||
|
|
||||||
|
**os-backlog migrated to planka-api 0.2.0 typed returns (2026-07-10):** commit `8df0cb7`
|
||||||
|
moved the gem from 0.1.0 hash-return to 0.2.0, which returns `Planka::Types` value objects
|
||||||
|
instead of parsed-JSON hashes. `board_ensurer.rb` and `cards.rb` were rewritten on typed
|
||||||
|
accessors (`card.id`, `card.list_id`, …); `Cards#snapshot` now builds explicit string-keyed
|
||||||
|
hashes from `BoardDetail#lists`/`#cards`/`#labels`/`#card_labels` (`BoardDetail` replaces the
|
||||||
|
old `included`-hash shape). Test fakes in `tests/test_helper.rb` were rebuilt to return real
|
||||||
|
`Planka::Types` records instead of hashes. JSON output stays byte-compatible, so skill/agent
|
||||||
|
contracts are unchanged. A follow-up fix (issue #18, same day) found the migration had
|
||||||
|
silently dropped one field from `Cards#snapshot`'s per-card hash; restored the full 19-key
|
||||||
|
camelCase card key set (`id`, `createdAt`, `updatedAt`, `type`, `position`, `name`,
|
||||||
|
`description`, `dueDate`, `isDueCompleted`, `stopwatch`, `commentsTotal`, `isClosed`,
|
||||||
|
`listChangedAt`, `boardId`, `listId`, `creatorUserId`, `prevListId`, `coverAttachmentId`,
|
||||||
|
`isSubscribed`, plus `labels`) with a regression test pinning the key set including
|
||||||
|
`listChangedAt`. Suite green at 35 runs (was 34 pre-#18).
|
||||||
|
|
||||||
|
**os-backlog live verification (0.2.0) (2026-07-10):** end-to-end re-verification of
|
||||||
|
`bin/os-backlog` against the real Planka instance with the installed 0.2.0 gem (issue #20).
|
||||||
|
Local machine had no `PLANKA_*` env/credvault entry, so the plugin tree was rsynced to
|
||||||
|
`ovh-vps:/tmp/os-backlog-verify` (where `planka-api` 0.2.0 is also installed) and exercised
|
||||||
|
there with bot credentials sourced from `~/services/planka/bot-credentials.env` in a
|
||||||
|
subshell, per the established pattern — credential contents were never read or printed.
|
||||||
|
Results: `tests/all.rb` 35 runs/0 failures on ovh-vps; `board-ensure cc-os --project Dev` run
|
||||||
|
twice both reported `(existing)` with no lists/labels created (idempotent); `card-add`
|
||||||
|
created a card on Backlog; `card-label` attached `afk-ready`; `card-comment` posted a
|
||||||
|
comment; `snapshot --board cc-os` showed the card with the full 20-key set (19 card fields +
|
||||||
|
`labels`) including `"listChangedAt": "2026-07-10T21:04:37.013Z"` and `"labels":
|
||||||
|
["afk-ready"]`. The test card was deleted via `Planka::Client#cards.delete` (the CLI has no
|
||||||
|
delete subcommand) and a follow-up snapshot confirmed it was gone; the rsynced verification
|
||||||
|
tree on ovh-vps was removed afterward. No regressions vs. the pre-0.2.0 behavior.
|
||||||
|
|
||||||
**Remaining optional items:** additional project onboarding (one at a time, per ADR-013); bulk
|
**Remaining optional items:** additional project onboarding (one at a time, per ADR-013); bulk
|
||||||
vault migration. All required build steps complete as of 2026-06-15.
|
vault migration. All required build steps complete as of 2026-06-15.
|
||||||
|
|
||||||
|
|
@ -499,7 +529,8 @@ symlinked into `~/.claude/plugins/os-backlog`; PRD Forgejo issue #9, slices #10
|
||||||
(Planka = task state by default; git issues = implementation specs only), mid-session
|
(Planka = task state by default; git issues = implementation specs only), mid-session
|
||||||
capture, pull-only listing, board lifecycle, and the three-value autonomy convention
|
capture, pull-only listing, board lifecycle, and the three-value autonomy convention
|
||||||
(`hitl`/`semi`/`afk-ready`).
|
(`hitl`/`semi`/`afk-ready`).
|
||||||
- Lib (Ruby, os-adr `lib/`+`bin/` pattern, installed planka-api gem only — no source
|
- Lib (Ruby, os-adr `lib/`+`bin/` pattern, installed planka-api gem only (0.2.0, typed
|
||||||
|
`Planka::Types` returns as of 2026-07-10) — no source
|
||||||
coupling): `board_spec.rb` (uniform lists/labels contract), `board_ensurer.rb`
|
coupling): `board_spec.rb` (uniform lists/labels contract), `board_ensurer.rb`
|
||||||
(idempotent create/repair; Planka 2.1.1 `type` fields, shared-project + owner-manager
|
(idempotent create/repair; Planka 2.1.1 `type` fields, shared-project + owner-manager
|
||||||
visibility fix, label color candidates with fallback; `archived--` rename convention),
|
visibility fix, label color candidates with fallback; `archived--` rename convention),
|
||||||
|
|
@ -520,7 +551,9 @@ symlinked into `~/.claude/plugins/os-backlog`; PRD Forgejo issue #9, slices #10
|
||||||
- Outstanding: Semi slices #14/#16/#17 (routing/migration skill, injection note +
|
- Outstanding: Semi slices #14/#16/#17 (routing/migration skill, injection note +
|
||||||
/to-issues routing, ops board + rubric category + routing ADR). Live verification
|
/to-issues routing, ops board + rubric category + routing ADR). Live verification
|
||||||
completed 2026-07-10 (snapshot / board-ensure / card-add / card-label against production;
|
completed 2026-07-10 (snapshot / board-ensure / card-add / card-label against production;
|
||||||
gem 0.1.0 locally installed via `rake install`).
|
gem 0.1.0 locally installed via `rake install`); re-verified 2026-07-10 (later) against the
|
||||||
|
installed 0.2.0 gem post-migration — see "os-backlog migrated to planka-api 0.2.0" and
|
||||||
|
"os-backlog live verification (0.2.0)" timeline entries above.
|
||||||
|
|
||||||
## Operational procedures
|
## Operational procedures
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,16 +76,30 @@ module Backlog
|
||||||
# Build the plain-hash card representation the CLI/JSON output emits,
|
# Build the plain-hash card representation the CLI/JSON output emits,
|
||||||
# keeping the output shape byte-compatible with the 0.1.x snapshot
|
# keeping the output shape byte-compatible with the 0.1.x snapshot
|
||||||
# (string keys, "labels" merged in) even though Types::Card is an
|
# (string keys, "labels" merged in) even though Types::Card is an
|
||||||
# immutable Data object we can no longer +merge+.
|
# immutable Data object we can no longer +merge+. Emits every
|
||||||
|
# Types::Card field — dropping fields here silently breaks consumers
|
||||||
|
# like board-audit, which reads "listChangedAt".
|
||||||
def card_hash(card, label_names)
|
def card_hash(card, label_names)
|
||||||
{
|
{
|
||||||
"id" => card.id,
|
"id" => card.id,
|
||||||
|
"createdAt" => card.created_at,
|
||||||
|
"updatedAt" => card.updated_at,
|
||||||
|
"type" => card.type,
|
||||||
|
"position" => card.position,
|
||||||
"name" => card.name,
|
"name" => card.name,
|
||||||
"description" => card.description,
|
"description" => card.description,
|
||||||
"position" => card.position,
|
|
||||||
"listId" => card.list_id,
|
|
||||||
"boardId" => card.board_id,
|
|
||||||
"dueDate" => card.due_date,
|
"dueDate" => card.due_date,
|
||||||
|
"isDueCompleted" => card.is_due_completed,
|
||||||
|
"stopwatch" => card.stopwatch,
|
||||||
|
"commentsTotal" => card.comments_total,
|
||||||
|
"isClosed" => card.is_closed,
|
||||||
|
"listChangedAt" => card.list_changed_at,
|
||||||
|
"boardId" => card.board_id,
|
||||||
|
"listId" => card.list_id,
|
||||||
|
"creatorUserId" => card.creator_user_id,
|
||||||
|
"prevListId" => card.prev_list_id,
|
||||||
|
"coverAttachmentId" => card.cover_attachment_id,
|
||||||
|
"isSubscribed" => card.is_subscribed,
|
||||||
"labels" => label_names
|
"labels" => label_names
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,23 @@ class CardsTest < Minitest::Test
|
||||||
assert_equal Backlog::BoardSpec::LABEL_NAMES.sort, snapshot["labels"].sort
|
assert_equal Backlog::BoardSpec::LABEL_NAMES.sort, snapshot["labels"].sort
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_snapshot_card_emits_complete_key_set
|
||||||
|
@cards.add(board_name: "llf-schema", title: "captured task")
|
||||||
|
|
||||||
|
snapshot = @cards.snapshot(board_name: "llf-schema")
|
||||||
|
backlog = snapshot["lists"].find { |l| l["name"] == "Backlog" }
|
||||||
|
card = backlog["cards"].first
|
||||||
|
|
||||||
|
expected_keys = %w[
|
||||||
|
id createdAt updatedAt type position name description dueDate
|
||||||
|
isDueCompleted stopwatch commentsTotal isClosed listChangedAt
|
||||||
|
boardId listId creatorUserId prevListId coverAttachmentId
|
||||||
|
isSubscribed labels
|
||||||
|
]
|
||||||
|
assert_equal expected_keys.sort, card.keys.sort
|
||||||
|
assert card.key?("listChangedAt"), "snapshot card must carry listChangedAt for board-audit"
|
||||||
|
end
|
||||||
|
|
||||||
def test_snapshot_includes_card_label_names
|
def test_snapshot_includes_card_label_names
|
||||||
card = @cards.add(board_name: "llf-schema", title: "labeled task")
|
card = @cards.add(board_name: "llf-schema", title: "labeled task")
|
||||||
p1 = @client.labels_store.find { |l| l.name == "P1" }
|
p1 = @client.labels_store.find { |l| l.name == "P1" }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue