Skip to content

feat(t2): Class A labeling fix for FR + SK + UK + SE YAML cleanup#133

Open
petterlindstrom79 wants to merge 2 commits into
mainfrom
feat/phase-1-class-a-relabel-fr-sk-uk
Open

feat(t2): Class A labeling fix for FR + SK + UK + SE YAML cleanup#133
petterlindstrom79 wants to merge 2 commits into
mainfrom
feat/phase-1-class-a-relabel-fr-sk-uk

Conversation

@petterlindstrom79
Copy link
Copy Markdown
Member

@petterlindstrom79 petterlindstrom79 commented May 18, 2026

Summary

Phase 1 of cost-free coverage sprint. Lifts EU30 binding-ready T2 from 2 (DE, GR) to 5 (DE, FR, GR, SK, UK). No per-call cost increase; all upstream sources already in use.

Three Class A audit-bug fixes (FR, SK, UK) plus one YAML drift cleanup (SE), per the 2026-05-18 verification reports (audit-output/registry-source-research-2026-05-18.md + handler-side directors verification).

What changed per country

  • FR (french-company-data.ts) — handler already emitted directors[] from INPI RNE via recherche-entreprises.api.gouv.fr; PR-131 labeling sweep wrongly set tier_2_available: false. Flipped to true, added legal_representatives canonical alias mirroring directors, rewrote reason string.
  • SK (slovak-company-data.ts) — handler already emitted directors[] from RPO statutoryBodies with active-only filter. Same Class A fix as FR.
  • UK (uk-company-data.ts) — bundled Companies House Officers extraction inline (new fetchOfficers() running in parallel with fetchCompany via Promise.all). legal_representatives[] populated with canonical {name, role, start_date} for active officers. Sibling capability uk-companies-house-officers.ts preserved standalone.
  • SE (swedish-company-data__se__company-registry.yaml) — annotation removed directors via Bolagsverket claim handler doesnt deliver. SE extraction deferred to Phase 4.

Verification

  • TSC: clean for files in this PR
  • Tests: 665 passed, 33 skipped, 0 failed (whole suite)
  • validate-capability.ts: SK 19/19; FR 19/20 + UK 19/20 — the single failed gate (company_name entry point lacks fixture) is pre-existing on main, not introduced by this PR
  • smoke-test.ts: SK 11/11 live; FR/UK 10/11 with step 2 blocked by cost_class=paid_prepaid ALLOW_MATRIX (expected, same on main)
  • checkReadiness: requires DATABASE_URL, skipped locally; covered by validate-capability ground

/go six-lens review — findings

Inline fixes applied (commit 87d21ae)

  • UK alias-guard consistency (Pass A architect/quality) — changed o.legal_representatives = officers; to if (o.legal_representatives === undefined) o.legal_representatives = officers; matching the surrounding canonical-alias block invariant.
  • UK fetchOfficers 404 swallow (Pass A senior-developer) — removed if (response.status === 404) return [];. Previously a 404 on the officers endpoint silently produced legal_representatives: [] with tier_2_available: true, making the flag misleading. Now propagates as a structured error consistent with fetchCompany.

MEDIUM findings flagged for chat-side decision (not blocking)

  1. Cross-country legal_representatives shape mismatch (Pass B product, originally HIGH) — FR/SK emit string[] ("FirstName LastName (Role)" and formatted-name respectively); UK emits Array<{name, role, start_date}>. A multi-country normalizer cannot treat them uniformly. This is prompt-directed (Phase 1 prompt said mirror existing directors array for FR/SK and structured shape for UK), so I did not auto-fix. Demoted from HIGH because the design was deliberate; surfacing here for explicit decision before customers bind to the contract. Two ways to close:
    • Normalize FR/SK to {name, role, start_date} (FR can split prenoms/nom/qualite; SK has only formatedName so role/start_date would be null).
    • Document the per-country shape variance in the manifest and accept the contract asymmetry.
  2. Manifest output_field_reliability gap (Pass A protocol) — manifests for FR / SK / UK do not yet declare legal_representatives. Per DEC-20260320-B Capability Onboarding Protocol the new field should be annotated (likely reliability: common — empty for shell entities or unpopulated cases). Follow-up PR.
  3. SE YAML roadmap leak (Pass B UX) — annotation reads 3/5 (VAT via VIES routing; directors integration planned Phase 4). The "planned Phase 4" phrasing bakes a roadmap promise into a coverage-matrix artifact. Consider rewriting to describe state only (e.g. directors not extracted from this source).
  4. tier_2_available_reason voice (Pass B UX) — the new strings read past-tense passive ("Legal representatives extracted from...") rather than caller-oriented ("Returns active legal representatives from..."). Voice diverges from the ubo_availability_reason style in the same files. Pattern-consistency call.
  5. UK 100-officer pagination cap (Pass B / efficiency) — items_per_page=100 with no follow-up page or legal_representatives_truncated flag. Rare edge case (FTSE-100 conglomerates with 100+ active officers + lifetime resignations), but mirrors the FR audit finding documented in docs/fr-directors-truncation-2026-05-15.md that we already fixed there. Consider parity.
  6. Companies House auth-header duplication (architect) — Basic ${Buffer.from(key + ":").toString("base64")} now appears 3× in uk-company-data.ts plus 1× in sibling uk-companies-house-officers.ts. Extract to a shared helper in a follow-up.

What this PR does NOT do

  • Does NOT delete uk-companies-house-officers (kept standalone)
  • Does NOT change the other 27 EU30 handlers
  • Does NOT add new vendor integrations
  • Does NOT update manifests for legal_representatives (flagged as follow-up)
  • Does NOT ship SE Funktionärer extraction (deferred to Phase 4)
  • Does NOT normalize FR/SK shapes to match UK (awaiting decision per MEDIUM add MCP server badge #1)

Doctrine

  • DEC-20260518-A — Evidence Tier framework (T2 Bindability semantics)
  • DEC-20260518-D — ubo_availability capability state (parallel pattern)
  • DEC-20260320-B — Capability Onboarding Protocol (manifest annotations follow-up)

Test plan

  • CI green (both check and Coverage matrix validation passed on c2e4974; re-running on 87d21ae)
  • Post-merge: production smoke test of FR Renault SIREN 441639465, SK Slovnaft ICO 31322832, UK Monzo CH 09446231 via /v1/do returning each handler — confirm tier_2_available: true and legal_representatives[] populated
  • MEDIUM add MCP server badge #1 decision — normalize shapes vs document asymmetry

Generated with Claude Code

Implements verified Class A findings from 2026-05-18 verification reports.
Flips tier_2_available to true on three handlers where the labeling
sweep wrongly set false despite handler emitting populated directors.

Per-country:
- FR: handler already emits directors[] from INPI RNE; flip flag, add
  legal_representatives canonical alias, rewrite reason string
- SK: handler already emits directors[] from RPO statutoryBodies; same
  pattern as FR
- UK: bundle uk-companies-house-officers extraction into uk-company-data
  so single CA call returns officers inline; flip flag, add alias
- SE: YAML annotation removed "directors via Bolagsverket" claim that
  handler doesn't deliver; Phase 4 ships SE extraction properly

Lifts EU30 binding-ready T2 from 2 (DE, GR) to 5 (DE, FR, GR, SK, UK)
with no per-call cost increase. Phase 1 of the cost-free coverage
sprint per 2026-05-18 launch-shape decision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
petterlindstrom79 added a commit that referenced this pull request May 18, 2026
Two inline fixes from the /go six-lens review on PR #133:

- Pass A correctness: removed 404 swallow in fetchOfficers. Previously
  the officers endpoint 404 silently produced legal_representatives=[]
  with tier_2_available=true, which made the flag misleading in the
  rare case where /company/{n} succeeds but /company/{n}/officers
  returns 404. Now the 404 propagates as a structured error consistent
  with fetchCompany.

- Quality consistency: guarded the legal_representatives assignment
  with the alias-block invariant pattern (if undefined). Matches
  surrounding canonical-alias resolution and FR sibling.

Deferred (PR-body MEDIUMs): cross-country shape mismatch, manifest
output_field_reliability gap, items_per_page=100 truncation guard,
SE YAML roadmap-state phrasing, reason-string voice, auth-header
duplication. See PR description for details.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two inline fixes from the /go six-lens review on PR #133:

- Pass A correctness: removed 404 swallow in fetchOfficers. Previously
  the officers endpoint 404 silently produced legal_representatives=[]
  with tier_2_available=true, which made the flag misleading in the
  rare case where /company/{n} succeeds but /company/{n}/officers
  returns 404. Now the 404 propagates as a structured error consistent
  with fetchCompany.

- Quality consistency: guarded the legal_representatives assignment
  with the alias-block invariant pattern (if undefined). Matches
  surrounding canonical-alias resolution and FR sibling.

Deferred (PR-body MEDIUMs): cross-country shape mismatch, manifest
output_field_reliability gap, items_per_page=100 truncation guard,
SE YAML roadmap-state phrasing, reason-string voice, auth-header
duplication. See PR description for details.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
petterlindstrom79 added a commit that referenced this pull request May 18, 2026
* feat(t2): Class A labeling fix for FR + SK + UK + SE YAML cleanup

Implements verified Class A findings from 2026-05-18 verification reports.
Flips tier_2_available to true on three handlers where the labeling
sweep wrongly set false despite handler emitting populated directors.

Per-country:
- FR: handler already emits directors[] from INPI RNE; flip flag, add
  legal_representatives canonical alias, rewrite reason string
- SK: handler already emits directors[] from RPO statutoryBodies; same
  pattern as FR
- UK: bundle uk-companies-house-officers extraction into uk-company-data
  so single CA call returns officers inline; flip flag, add alias
- SE: YAML annotation removed "directors via Bolagsverket" claim that
  handler doesn't deliver; Phase 4 ships SE extraction properly

Lifts EU30 binding-ready T2 from 2 (DE, GR) to 5 (DE, FR, GR, SK, UK)
with no per-call cost increase. Phase 1 of the cost-free coverage
sprint per 2026-05-18 launch-shape decision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* review: address /go six-lens findings inline (UK)

Two inline fixes from the /go six-lens review on PR #133:

- Pass A correctness: removed 404 swallow in fetchOfficers. Previously
  the officers endpoint 404 silently produced legal_representatives=[]
  with tier_2_available=true, which made the flag misleading in the
  rare case where /company/{n} succeeds but /company/{n}/officers
  returns 404. Now the 404 propagates as a structured error consistent
  with fetchCompany.

- Quality consistency: guarded the legal_representatives assignment
  with the alias-block invariant pattern (if undefined). Matches
  surrounding canonical-alias resolution and FR sibling.

Deferred (PR-body MEDIUMs): cross-country shape mismatch, manifest
output_field_reliability gap, items_per_page=100 truncation guard,
SE YAML roadmap-state phrasing, reason-string voice, auth-header
duplication. See PR description for details.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(t2): Phase 2 legal_representatives extraction for NO

Adds extraction of legal_representatives[] from Brreg /roller endpoint
to norwegian-company-data.ts. Flips tier_2_available: true. Cost-free
(uses existing free anonymous Brreg endpoint; name + birth date only,
fnr requires Maskinporten which is out of scope here).

Canonical shape: { type, name, role, role_code, role_group, date_of_birth }
mirroring italian-company-stakeholders. role_group is Brreg rollegruppe
(STYR, DAGL, SIGN, PROK, etc.); role_code is the per-member rolletype
(LEDE/NEST/MEDL/VARA/OBS for STYR; same as group for single-role groups).
Filters out resigned (fratraadt) and deregistered (avregistrert) roles.

Live verified:
- Equinor ASA (923609016): 16 active representatives extracted

Lifts binding-ready T2 by +1. Phase 2 of cost-free coverage sprint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(coverage-matrix): regenerate COVERAGE.md for NO last_verified bump

Picks up the 2026-05-18 last_verified shift on norwegian-company-data
from the previous commit. CI gate `coverage-matrix:check` requires
COVERAGE.md to be in sync with the per-row YAML files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant