feat(plantare): schema v12 — bilateral signed columns + repo

Adds the deferred bilateral columns to Plantares (plantare-bilateral.md
§"Schema delta"), all nullable/defaulted so v1 local rows coexist
untouched:

- pledgeId (the shared id both parties key their row by), debtorKey /
  creditorKey, debtorSignature / creditorSignature, movementId (the
  shared hand-over Movement for the provenance DAG), remoteState
  (proposed/accepted/declined — the handshake, distinct from status),
  returnKind (similar/workHours/other, default similar) + workHours.

Repo: createPlantare grows optional bilateral params; plantareByPledgeId
looks a row up by the shared id; applyPlantareSignatures counter-stamps
an incoming accept; setPlantareRemoteState records a decline. The
JSON codec carries every new field so they ride backups.

Versioned migration is guarded/idempotent like the others; schema v12
dumped, test helper regenerated, migration test covers v1..v11 → v12.
db + data + services 295/295 green.
This commit is contained in:
vjrj 2026-07-14 10:59:35 +02:00
parent 3f622f7bf7
commit 01fba40ec2
11 changed files with 5322 additions and 17 deletions

View file

@ -221,6 +221,39 @@ class Plantares extends Table with SyncColumns {
IntColumn get settledOn => integer().nullable()();
TextColumn get note => text().nullable()();
// --- Bilateral signed form (plantare-bilateral.md). Nullable so v1 local rows
// (both keys/signatures null, remoteState null) coexist untouched. ---
/// The shared pledge id both parties agree on (the proposer's id). Distinct
/// from [id] (each side keeps its own local row). Null for a v1 local note.
TextColumn get pledgeId => text().nullable()();
/// Pubkey (hex) of who received the seed and owes a return.
TextColumn get debtorKey => text().nullable()();
/// Pubkey (hex) of who gave the seed.
TextColumn get creditorKey => text().nullable()();
/// The debtor's Schnorr stub over the canonical pledge core.
TextColumn get debtorSignature => text().nullable()();
/// The creditor's Schnorr stub over the canonical pledge core.
TextColumn get creditorSignature => text().nullable()();
/// The shared hand-over `Movement` this Plantare accompanies (provenance DAG).
TextColumn get movementId => text().nullable()(); // Movement
/// The handshake state (proposed/accepted/declined), null for a v1 local row.
TextColumn get remoteState => textEnum<PlantareRemoteState>().nullable()();
/// How it's promised back (default `similar`: open-pollinated · non-GMO ·
/// organically grown), mirroring the paper form's checkboxes.
TextColumn get returnKind =>
textEnum<PlantareReturnKind>().withDefault(const Constant('similar'))();
/// Hours for the `workHours` return option (time-as-currency). Null otherwise.
RealColumn get workHours => real().nullable()();
}
/// A recorded seed Sale seed for money (data-model §2.8/sharing-model §6). A