Files
pad/internal/server
xarmian 115b33849e feat(templates): software starter pack + idempotent seeding (TASK-612) (#144)
* feat(templates): software starter pack + idempotent seeding (TASK-612)

Ship the software templates (startup, scrum, product) with a curated
starter pack of conventions + playbooks so new workspaces feel
"batteries included" rather than empty shells. The pack is a safe,
small subset drawn from the existing convention/playbook library —
the library itself remains the full catalog for interactive onboarding.

Starter pack contents
---------------------
Conventions (4):
- Conventional commit format (on-commit, should)
- Never push directly to main (on-commit, must)
- Run tests before completing tasks (on-task-complete, must)
- Review your own changes before PR (on-pr-create, should)

Playbooks (2):
- Implementation Workflow (on-implement)
- Code Review Process (on-review)

The pack is materialized by looking up library items by title and
converting them to SeedConvention / SeedPlaybook via json.Marshal of
the expected field shape. When the library's wording changes, the
template's seed content changes automatically.

Store-side changes
------------------
SeedCollectionsFromTemplate is now idempotent with respect to seed
items: items are only created in collections that were freshly
created during the current call (tracked via a freshlyCreated set).
That's the invariant that lets the server's startup auto-upgrade
safely re-run on every boot without duplicating items across every
workspace in the DB.

Empty template name preserves the old behavior (default collections,
no starter pack) — this keeps backward compatibility for callers that
don't pass a template, including the server-startup auto-upgrade path
and all existing server tests. Explicit "startup" / "scrum" / "product"
now gets the starter pack.

Tests
-----
- TestSoftwareStarterPacksPopulated — guards against library-title drift
- TestSoftwareTemplatesShipStarterPacks — each software template ships a pack
- TestSeedCollectionsFromTemplateSeedsStarterPack — end-to-end seeding works
- TestSeedCollectionsFromTemplateIdempotentWithSeedItems — re-seed doesn't duplicate

Parent: PLAN-609.

* fix(cli): default pad init to startup template when --template is omitted

Per Codex review on PR #144. Without this, `pad workspace init` without
`--template` no longer seeded the starter pack, even though startup is
documented as the default. The fix lives in ensureWorkspace (shared by
both init.go and the workspace creation command in main.go) — empty
flag is rewritten to "startup" there. Tests and other direct API
callers that want an empty workspace still pass Template="" through.

* fix(cloud): auto-create workspace passes startup template for starter pack

Per Codex review iteration 2 on PR #144. The auto-create cloud-signup
flow calls SeedCollectionsFromTemplate with an empty template, which
after this PR's semantics meant new cloud workspaces got no starter
conventions/playbooks. Pass "startup" explicitly to match the CLI
init behavior.

* fix(store): propagate collection lookup errors during seeding

Per Codex review iteration 3 on PR #144. seedItem previously treated
any error from GetCollectionBySlug as a silent no-op, which hid real
DB lookup failures — a transient error during workspace creation would
make seeding appear successful while conventions/playbooks were in
fact missing. Now we distinguish the two cases:

  - err != nil  → propagate so callers can detect partial init
  - coll == nil → benign (template references a slug not in its
                   collections list; template-author bug, no-op)

* fix(store): idempotent seeding by item title (partial-init recovery)

Per Codex review iteration 4 on PR #144. The previous design gated
item seeding on collections being freshly-created-in-this-call, which
trapped partially-initialized workspaces: if a DB error fired between
collection creation and item seeding, a retry would see the
collections already existed and skip every remaining seed item.

Switch to title-based idempotency. Before inserting a seed item we
list the target collection's existing items (once per collection, via
a small cache) and skip any whose title already exists. That makes
seeding:

- Idempotent: re-running a template doesn't duplicate items
- Recoverable: retrying fills in missing items after partial init
- Retry-safe: the auto-upgrade path can re-run safely on every boot

New test TestSeedCollectionsFromTemplateRecoversPartialInit exercises
the recovery path explicitly.
2026-04-18 01:22:08 -04:00
..
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00