feat(parties): the register fills the row, a compact Företagsuppgifter, and the party for agents (v1 expand + MCP) (#2315)

* feat(parties): the register fills the row, Företagsuppgifter shrinks to what only the register knows, and agents get the party

Founder feedback on the first Företagsuppgifter (2026-09-05): the org
number twice, the VAT number twice, the legal name repeating the
heading, and Kontaktuppgifter showing dashes while the block above had
the phone, e-mail and address from SCB.

- After a fetch the register's contact details land on the supplier and
  customer rows that point at the party: an empty field, or one still
  carrying what the register said last time, takes the new value; a
  value a person typed stays. Shown as "från SCB" on the row (by
  equality with the registry fact, no source column).
- Företagsuppgifter becomes one status line (legal form, active or not,
  registrations, a Bolagsverket warning when there is one), industry,
  seat with registration date, and size. Identity stays in the header
  (org number now formatted) and Kontaktuppgifter. The legal name shows
  only when it differs from the row's name.
- lib/parties/registry-summary.ts reads the coded SCB facts once for the
  page, the v1 API and MCP; lib/parties/party-api.ts is the agent shape.
- v1: party_id on supplier and customer list rows and detail;
  ?expand=party on detail embeds identity, the register summary, what
  the ledger has seen and payment identities. MCP: party_id on
  gnubok_list_suppliers/customers rows and gnubok_get_party (by party,
  supplier or customer id). Read-only; the parties resource follows.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore(parties): regenerate the API skill for the party expansion; tighten the get_party description

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore(mcp): gnubok_get_party is search-only, keeping tools/list under its byte budget

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-09-05 14:33:20 +02:00
committed by GitHub
co-authored by Claude Fable 5.1 Jakob Wennberg
parent f33628f005
commit 0ad83b8d71
21 changed files with 881 additions and 85 deletions
+1
View File
@@ -1600,3 +1600,4 @@ One line per decision: `[YYYY-MM-DD] <decision>: <why>`. Appended by agents and
[2026-09-05] Provider OAuth returns to the initiating validated app/brand origin through a two-minute provider_otc handoff. State rows and handoffs have disjoint consume predicates, handoff consumption also binds the destination origin, and both success and provider denial require the original user on hop 2. The token exchange keeps the original configured provider redirect URI. Staging prerequisites 20260831111519, 20260902090000 and 20260902100000 were replayed from the existing SQL files before 20260905094806; MCP-assigned history timestamps were reconciled to those repository versions. Production and the live amnas Fortnox connect remain pending deployment and specific production-write approval.
[2026-09-05] PR #2305 review: encrypt both OAuth handoff payload columns with AES-256-GCM using a purpose-scoped derivation of the existing server-only service-role secret, matching other extension credential storage. Authenticate the handoff token, consent, initiating user, destination origin and column as additional data; reject plaintext or unreadable payloads after atomic consume. This resolves the at-rest encryption finding without new configuration, dependencies, or edits to the already-applied migration.
[2026-09-05] PR #2305 cleanup review: expire provider_otc rows through a service-role cron every five minutes, including abandoned states and encrypted handoffs whose consents remain. Use the existing cron-auth wrapper and generated hosted/self-hosted schedules; the migration is already applied on staging and remains unchanged.
[2026-09-05] Supplier and customer pages: the register fills the row's own contact fields (e-mail, phone, postal address, VAT number) when they are empty or still carry what the register said last time, marked "från SCB" by equality with the registry fact, never a value a person typed. Chosen over a read-only fallback because the row is what payment files and documents use; provenance by equality instead of a source column because it needs no schema and a person's edit ends it by itself. Företagsuppgifter keeps only what the register alone knows (status line, industry, seat, size). Agents get the party read-only first: ?expand=party on v1 supplier/customer detail, party_id on list rows, and gnubok_get_party in MCP; the parties resource (suggest, promote, enrich) comes as its own v1 surface next.