Files
settled-reach/pql-requirements.md
T
jpmschweitzerandClaude Opus 4.8 07e5ba005d docs(meta): pql migration plan + requirements for the pql team
Deep analysis of migrating decisions + ticketing from the SQLite CLI to pql:
- pql-migration.md: phased branch-only plan (decisions→DQR tree, ticket changelog
  seed with T-N≡#N, #N→T-N find-replace, big-bang consumer cutover, docs/workshops/
  wiki fold-in, SQLite retirement) + verification gate + benefits.
- pql-requirements.md: 9 surfaced gaps for the pql team (critical: seeded ticket
  ids + counter-advance; high: dup-id detection, core.hooksPath awareness, changelog
  seed-format docs).

Key finding: milestones are vestigial (milestone_deps empty, 42/1013 tickets
linked) → mapped to a label, dropped as an entity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 11:37:52 +02:00

8.4 KiB

title, description, type, status, created, updated, tags
title description type status created updated tags
pql Requirements — gaps surfaced by the Settled Reach migration Feature gaps and friction points found while migrating a 1013-ticket + 358-decision project onto pql, for the pql team requirements draft 2026-06-06 2026-06-06
pql
requirements
feedback

pql Requirements — gaps for the pql team

Compiled while planning a migration of The Settled Reach (a Godot+Rust game) off a SQLite-backed ticket CLI + markdown-decisions-sync onto pql. Scale: 1013 tickets, 481 dependency edges, 48 labels, 16 history rows; 358 decision records (237 D / 109 Q / 12 R) with 1040 cross-refs; a ~4385-file markdown vault (decisions, docs, 22 workshops, ~3500 wiki pages).

pql is a strong fit and most of our system maps cleanly. The items below are the gaps we hit. Each lists why we need it, a suggested shape, and a priority. Where we have a viable workaround, it's noted — but the workaround is friction we'd rather not ship.


1. Seeded / explicit ticket IDs + id-counter advance — CRITICAL

Why. Our 1013 tickets have integer ids referenced as #440 in thousands of immutable git commits, in decision "Ticket: #N" lines, and by our PR automation. We need the pql id to preserve the number — T-440 ≡ old #440 — so the mapping stays a trivial bijection. pql's id is a TEXT column, so we can seed 'T-440' directly into the changelog. But pql ticket new auto-assigns T-N sequentially starting at T-1 — after seeding T-1…T-1013, the next native create would mint T-1 and collide.

Suggested shape.

  • pql ticket new --id T-1014 (accept an explicit id), AND/OR
  • on pql plan rebuild/import, advance the internal id counter past the max existing id so native creates never recycle a seeded id.

Workaround. None safe — we'd have to hold all native ticket creation until this lands, or hand-manage a sentinel. This is the one true blocker for a clean numbered migration.


2. Duplicate-ID detection in pql decisions sync / validateHIGH

Why. Our markdown had a genuine integrity bug: D-035 defined in two domain files, R-011 defined three times. pql decisions sync silently last-writer-wins-collapsed them (reported broken: 0), so the duplication was invisible. Our legacy Python check-dupes errors on it. A duplicate canonical-ID is almost always a data bug, not an intended merge.

Suggested shape. pql decisions validate (and sync --strict) should warn or error on duplicate D/Q/R ids across the vault, reporting file:line for each occurrence.

Workaround. Keep our Python check-dupes wired into pre-commit alongside pql — extra tooling we'd like to retire.


3. core.hooksPath awareness in pql initHIGH

Why. Our repo sets core.hooksPath = .config/hooks (so hooks are version-controlled). pql init installs its pre-commit/post-merge/post-checkout hooks into .git/hooks/, which git ignores when core.hooksPath is set. pql's changelog-staging + replay hooks would be silently dead — the whole durable-versioning model depends on them. This is a quiet, dangerous failure (data appears to work, but .pql/changelog/ is never staged).

Suggested shape. pql init/pql doctor should detect core.hooksPath and either install into the configured dir or emit a loud warning with the manual fold-in snippet.

Workaround. Manually fold pql's hook logic into .config/hooks/* (we will), but pql doctor should flag the mismatch so others don't get bitten.


4. Document the changelog seed format + hash/canonical_version algorithm — HIGH

Why. pql plan import --legacy is documented as retired; the real durable artifact is .pql/changelog/<table>/<YYYY-MM>.sql. To migrate 1013 tickets we must emit those SQL rows directly. We reverse-engineered the UPSERT shape, but the per-row hash and canonical_version columns + the LWW guard (WHERE excluded.updated_at > … OR (… AND excluded.hash > …)) are opaque. If our seed hashes don't match pql's scheme, later native edits still win by updated_at (so correctness holds), but the LWW tie-break becomes unpredictable.

Suggested shape. Document (a) the canonical changelog row format per table, (b) the hash input + algorithm, (c) how canonical_version increments — OR provide a supported one-shot pql plan seed <json|csv> import that computes them.

Workaround. Emit our own stable per-row hash; rely on updated_at for correctness. Works, but under-specified.


Why. Across ~4385 vault files (esp. ~3500 generated wiki pages), decision/ticket references are mostly bare text (D-117, #440) rather than markdown/wikilinks. pql search finds them, but pql backlinks/related only follow real links — so "what references D-117?" is incomplete. Rewriting 3500+ generated files to add links is impractical (they're regenerated from a pipeline).

Suggested shape. Optional reference recognizers (configurable regex → entity, e.g. D-\d+→decision, T-\d+→ticket) so backlinks/related treat bare-text mentions as edges without requiring link syntax in source.

Workaround. Adopt a link convention in authored files only; accept that generated files are search-only.


6. WIP-limit enforcement (advisory) on ticket status … in_progressMEDIUM

Why. Our kanban flow enforces a WIP limit (max 5 in_progress); our activation step relied on the CLI warning when exceeded. pql has no forced state machine / WIP concept.

Suggested shape. An optional config (wip_limit: 5) that makes pql ticket status <id> in_progress emit an advisory warning (not a hard block) when the in_progress count would exceed it.

Workaround. Compute pql ticket list --status in_progress | count in our skill and warn there.


7. Fan-out / downstream-unblock count on ticket showMEDIUM

Why. Our batch-selection ranks ready tickets partly by fan-out — how many downstream tickets a ticket unblocks. We currently compute it from the dependency graph. pql has --unblocked (great — it replaced our manual blocker walk) but no "how many does this unblock" signal.

Suggested shape. A blocks_count / unblocks_count field on pql ticket show/list, or a pql ticket list --orders-by fanout.

Workaround. Compute client-side from ticket show --with-context dep data.


8. Multi-team / array team field — LOW

Why. One ticket carries a comma-separated team (client,server). pql treats team as a single string. (1 of 1013 — genuinely low.)

Suggested shape. Accept an array/comma team, or document the single-team constraint.

Workaround. Pick the primary team for the one affected ticket.


9. Bless a "labels-as-milestones" pattern (or an optional milestone entity) — LOW / nice-to-have

Why. Our schema has a milestones subsystem (milestones, ticket_milestones, milestone_deps, cascade_phase) — but in practice it's vestigial: 2 milestones (1 active, 1 completed-with-0-tickets), milestone_deps empty, 42/1013 tickets linked, cascade ordering never used. We're mapping the one active milestone to a label (phase:4) and dropping the rest. This works today, so it is not blocking.

Suggested shape. Either bless labels-as-milestones as the documented pattern (with helper queries / rollups), or offer an optional lightweight milestone entity (M:N ticket links, status, ordering, done/total rollups) for projects that actually use phase gating. We'd only need the latter if we later adopt real cross-phase dependency gating.


Summary

# Requirement Priority Have workaround?
1 Seeded/explicit ticket id + counter-advance Critical No (real blocker)
2 Duplicate-ID detection in sync/validate High Yes (keep our checker)
3 core.hooksPath awareness High Yes (manual fold-in)
4 Documented changelog seed format + hash algo High Partial
5 Bare-text ref detection for backlinks Medium Partial (authored files only)
6 WIP-limit advisory Medium Yes (skill-side)
7 Fan-out / unblocks count Medium Yes (client-side)
8 Multi-team field Low Yes
9 Labels-as-milestones blessing / optional entity Low Yes (labels)