vouchington-tooling 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +5 -1
  2. package/dist/agent-blackboard/feedback-canonical.d.mts +7 -0
  3. package/dist/agent-blackboard/feedback-canonical.mjs +8 -0
  4. package/dist/agent-blackboard/feedback-delivery.mjs +8 -6
  5. package/dist/agent-blackboard/feedback-online.mjs +11 -4
  6. package/dist/agent-blackboard/feedback-outbox.d.mts +8 -1
  7. package/dist/agent-blackboard/feedback-outbox.mjs +17 -4
  8. package/dist/agent-blackboard/feedback-types.d.mts +4 -0
  9. package/dist/agent-blackboard/index.d.mts +1 -1
  10. package/dist/agent-blackboard/index.mjs +1 -1
  11. package/dist/cli/index.mjs +4 -0
  12. package/dist/cli/parse.d.mts +1 -1
  13. package/dist/cli/parse.mjs +1 -0
  14. package/dist/cli/usage.d.mts +1 -1
  15. package/dist/cli/usage.mjs +2 -0
  16. package/dist/mcp-server/dispatch.mjs +5 -4
  17. package/dist/mcp-server/fake-blackboard.test-helpers.d.mts +3 -0
  18. package/dist/mcp-server/fake-blackboard.test-helpers.mjs +7 -1
  19. package/dist/mcp-server/handlers-journal.d.mts +0 -2
  20. package/dist/mcp-server/handlers-journal.mjs +22 -30
  21. package/dist/mcp-server/handlers-outbox.d.mts +11 -0
  22. package/dist/mcp-server/handlers-outbox.mjs +45 -0
  23. package/dist/mcp-server/harness.test-helpers.d.mts +6 -1
  24. package/dist/mcp-server/harness.test-helpers.mjs +14 -2
  25. package/dist/mcp-server/server.mjs +5 -1
  26. package/dist/mcp-server/tools.mjs +12 -10
  27. package/dist/pnpm-install/pnpm-install-fake-pnpm.test-helpers.mjs +2 -2
  28. package/docs/mcp-server.md +58 -14
  29. package/package.json +3 -3
  30. package/scripts/gha/gha-collaborator-trust.sh +75 -0
  31. package/skills/blackboard/SKILL.md +27 -17
  32. package/skills/manifest.json +27 -21
  33. package/skills/postgres-node-performance-tuning/references/performance-patterns.md +22 -0
  34. package/skills/postgres-partitioning-uuid-v7/SKILL.md +3 -0
  35. package/skills/postgres-schema-design/SKILL.md +21 -0
  36. package/skills/postgres-schema-design/references/naming.md +34 -0
  37. package/skills/postgres-schema-design/references/relations.md +46 -0
  38. package/skills/postgres-schema-design/references/table-shapes.md +56 -0
  39. package/skills/retrospective-distill/SKILL.md +13 -8
@@ -0,0 +1,46 @@
1
+ # Relations
2
+
3
+ An identity that readers join is an FK column or an FK child row. JSON holds structured,
4
+ schemaless data and history snapshots, including identities recorded as they were at the time.
5
+ Do not use UUID arrays, JSON ids, or type/id pairs for live relations. A column never names a
6
+ table: use one table per target and generate any per-relation progress enum from the same metadata.
7
+ Cursor positions and random fencing tokens are intentionally not live entity references; record
8
+ their reviewed exception instead of inventing a foreign key.
9
+
10
+ Split tables when their columns or FK targets differ; share a table when only a value differs.
11
+ Identical lookup values share a row without a source discriminator. Put subtype-only columns in
12
+ a subtype table whose primary key also references the base row (`business_accounts.account_id`
13
+ references `accounts.id`). A 1:N child remains an ordinary child table.
14
+
15
+ For one of several sources, use an exclusive arc:
16
+
17
+ ```sql
18
+ CHECK (num_nonnulls(order_id, invoice_id) = 1)
19
+ ```
20
+
21
+ Both source columns have their own FK. If a reference must belong to the same account, enforce
22
+ `FOREIGN KEY (account_id, invoice_id) REFERENCES invoices (account_id, id)` with a corresponding
23
+ unique key on the target. A validation trigger is unnecessary. With nullable `invoice_id`,
24
+ default `MATCH SIMPLE` skips that composite check when the reference is absent.
25
+
26
+ A ledger that survives deletion references a retained identity row with explicit deletion
27
+ behavior. Retained identities preserve history; they do not authorize operations on a deleted
28
+ account, order, or invoice. Index FK columns with a leading key usable by referential checks.
29
+
30
+ Finite code-defined values use enums. Use a lookup table when values carry attributes or arrive
31
+ at runtime. Authenticated vendor-defined values are inserted into a shared lookup on first sight,
32
+ with validation and concurrent insertion handled explicitly. Do not let untrusted strangers
33
+ create unbounded permanent lookup rows; reviewed raw text can be appropriate for their input.
34
+ Free text and a lookup's own natural key are not finite sets.
35
+
36
+ Arrays are for enums or outside-defined lists; live identity collections use FK child rows,
37
+ never `uuid[]`. User-submitted URLs go through one registry with centralized normalization and
38
+ validation, then use URL FKs. Keep exact external protocol identifiers, capability URLs, and
39
+ evidence snapshots unchanged when their contract requires it; document the exception.
40
+ Do not duplicate a child collection into a parent column unless a trigger maintains the projection.
41
+
42
+ Generic enforcement in `jonathanong/no-mistakes`: `postgres-column-naming`,
43
+ `postgres-array-columns`, `postgres-table-shape`, `postgres-fk-index`, and
44
+ `postgres-require-fk-on-delete`. These cover naming, configured shapes, and FK mechanics;
45
+ inspect the installed rule versions and options rather than assuming complete semantic coverage.
46
+ Comments and reviewed exceptions remain necessary.
@@ -0,0 +1,56 @@
1
+ # Table shapes
2
+
3
+ Choose a shape by lifecycle and meaning. Do not store hand-synchronized status beside lifecycle
4
+ timestamps. A final lifecycle derives enum status with an immutable generated expression over
5
+ timestamps such as `claimed_at`, `completed_at`, and `failed_at`. A time-based expiry needs an
6
+ explicit sweeper-written timestamp; `now()` cannot appear in an immutable generated expression.
7
+ When state keeps returning to earlier states, record append-only attempts or changes and derive
8
+ current state from the latest row rather than erasing the previous lifecycle.
9
+
10
+ | Concept | Shape |
11
+ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
12
+ | Field-diff history | `<entity>_revisions`: UUIDv7 `id`, entity FK, nullable revision actor FK with `ON DELETE SET NULL`, revision-type enum, `changes jsonb`. |
13
+ | Typed lifecycle ledger | `<entity>_changes`: UUIDv7 `id`, entity FK, change-type enum, retained actor identity FK with `ON DELETE RESTRICT`, typed joined payload and JSON for unjoined data. Time comes from `id`. |
14
+ | Current state from a log | Latest change by `id DESC`, projected through a shared trigger or read through a view. |
15
+ | Per-entity work | `<entity>_<job>_work_items`: entity FK, lease and final-outcome columns, claim index, retention. |
16
+ | Job progress | `<job>_cursors`: finite enum key or checked singleton, keyset positions without FKs, optional sweep upper bound. |
17
+ | Inbound or protocol events | Append-only `<source>_events` with `occurred_at` recording the event's business time. |
18
+
19
+ Revisions and changes are append-only through a generic `fn_reject_mutation`, parameterized by
20
+ actor columns that may be erased to NULL. Permit only those erasures; parent-cascade deletion
21
+ may be permitted by policy. A trigger-depth test alone cannot prove a delete came from a parent
22
+ cascade, because another trigger also increases depth. Do not copy the parent into each ledger
23
+ row. Keep historical before/after snapshots as JSON rather than joined history child tables.
24
+ A system change has a NULL actor. Retained actors remain historical identities, without authority.
25
+
26
+ ## Work leases
27
+
28
+ The lease lives on a row that exists only for the work. If an invoice outlives a delivery job,
29
+ use `invoice_delivery_work_items`, with an invoice FK and `ON DELETE CASCADE`, rather than putting
30
+ the lease on the invoice. Do not create a shared polymorphic lease table.
31
+
32
+ Use `lease_token uuid`, `leased_at`, `lease_expires_at`, `attempt_count`, `available_at`, and
33
+ `completed_at` plus timestamps for final outcomes. Add `generation` only when re-enqueue can race
34
+ a running worker. Each claim or reclaim gets a fresh opaque token. Every renewal, completion,
35
+ and failure must include `WHERE lease_token = $mine`; zero affected rows means ownership was lost.
36
+ Keep retries in an optional `_attempts` ledger with `attempt_number` when their lifecycle must
37
+ survive. One-shot compare-and-set claims and human assignments need their own shapes.
38
+
39
+ ## Cursors and shared functions
40
+
41
+ A cursor key names the finite thing being swept. A singleton uses
42
+ `is_singleton boolean PRIMARY KEY DEFAULT true CHECK (is_singleton)`; the job seeds its own row
43
+ with `ON CONFLICT DO NOTHING`. `cursor_<thing>_id` and optional `sweep_upper_bound_<thing>_id` are
44
+ FK-free UUIDv7 positions; NULL means the start. Per-unit work progress belongs in work items.
45
+ A UUIDv7 is assigned at insert, not commit: jobs that must see every committed row re-scan an
46
+ overlap rather than assuming an id high-water mark proves commit order.
47
+
48
+ Use `updated_at` only for mutable rows, always maintained by its trigger; application code never
49
+ writes it. Comment every table, column, and view, including generated objects. Self-explanatory
50
+ columns may have explicit reviewed local exceptions; view comments describe their reader boundary.
51
+ Reuse generic trigger functions with `TG_ARGV` and `TG_TABLE_NAME`; quote dynamic identifiers
52
+ with `format('%I', ...)`. A trigger function and a SQL-callable helper are separate functions.
53
+
54
+ Generic enforcement in `jonathanong/no-mistakes`: `postgres-table-shape` and
55
+ `postgres-duplicate-function-body`. Configure canonical shapes explicitly and verify which
56
+ rules the installed release supports; lifecycle and authority decisions still need review.
@@ -17,11 +17,15 @@ Use when completed retrospectives or journals should become durable follow-up wo
17
17
  `data` fields, `dataArrayContains`, and `inactiveForHours`. It exports non-archived sessions to a
18
18
  private local file and returns the path, counts, checksum, and manifest, never the records.
19
19
  Before exporting, call `outbox_flush` and then `outbox_status` for every worktree that
20
- `git worktree list` reports, passing each path as `worktree`, and stop if any still reports
21
- pending records: an archived session refuses later delivery, so a retained record would never
22
- be distilled. Outboxes in removed worktrees or on other machines cannot be drained this way, so
23
- select with `inactiveForHours` to give them time to deliver. Leave in-progress sessions intact.
24
- If the server is not connected, stop and report it; do not fall back to a CLI command.
20
+ `git worktree list` reports, passing each path as `worktree`, and stop if any reports a
21
+ `worktreePendingCount` above 0. Use the worktree count, never `pendingCount` or `status`, which
22
+ cover only the caller's own session: the sessions to distill belong to other agents, and an
23
+ archived session refuses later delivery, so a retained record would never be distilled. Outboxes
24
+ in removed worktrees or on other machines cannot be drained this way, so select with
25
+ `inactiveForHours` to give them time to deliver. Leave in-progress sessions intact. If a search
26
+ for `snapshot_export` (the tool names carry a harness prefix, see the
27
+ [blackboard skill](../blackboard/SKILL.md)) finds no server, stop and report it; do not fall back
28
+ to a CLI command.
25
29
  2. Before using any record, verify the file against the returned checksum, counts, and terminal
26
30
  manifest with the consumer's approved snapshot reader, and stop on a mismatch rather than
27
31
  treating missing records as absent. Read full records, with their storage type, repository
@@ -34,7 +38,8 @@ Use when completed retrospectives or journals should become durable follow-up wo
34
38
  3. Validate storage type and the shared envelope independently of optional category. Never repair
35
39
  unknown legacy types or repository provenance by inference. Quarantine malformed sessions with
36
40
  an explicit reason while processing valid unrelated sessions. Deduplicate at-least-once records
37
- by exact session/source identity and reject conflicting duplicate content. Retain coverage,
41
+ by exact session/source identity and reject conflicting duplicate content. Records that differ
42
+ only in their server-assigned `timestamp` are one event. Retain coverage,
38
43
  dropped counts, requested versus observed outcomes, and useful resolved findings.
39
44
  4. Cluster findings by root cause. Prefer a few broad actionable themes over many narrow issues.
40
45
  Treat a finding already linked to an open tracker as context, not a duplicate.
@@ -47,8 +52,8 @@ Use when completed retrospectives or journals should become durable follow-up wo
47
52
  [github-issue](../github-issue/SKILL.md), including its repository gate, label approval, and
48
53
  denied-external tracking behavior.
49
54
  7. Archive only verified records fully processed across every represented repository, and never
50
- while any worktree's `outbox_status` reports pending records, under the repository's retention
51
- rules. Make one `session_archive` call per session, whose `sessionId` is the archived session,
55
+ while any worktree's `outbox_status` reports a `worktreePendingCount` above 0, under the
56
+ repository's retention rules. Make one `session_archive` call per session, whose `sessionId` is the archived session,
52
57
  not the caller. Immediately before each call, read that session with `journal_entries` and
53
58
  archive only if its entries match the verified snapshot's by source identity; otherwise leave it
54
59
  for the next pass, because an entry added after the export would never be distilled.