Skip to content

Make iids-portfolio vocabulary parity a CI error - #319

Merged
ProfessorPolymorphic merged 1 commit into
mainfrom
ci/verify-governance-vocab-parity
Jul 27, 2026
Merged

Make iids-portfolio vocabulary parity a CI error#319
ProfessorPolymorphic merged 1 commit into
mainfrom
ci/verify-governance-vocab-parity

Conversation

@ProfessorPolymorphic

Copy link
Copy Markdown
Collaborator

The scoping drift closed in #318 should never have been findable only by hand. ADR 0001's amendment named the upstream registration as a follow-up, the follow-up was missed, a project shipped claiming the status, and every check stayed green for three days.

My first suggestion was wrong

I proposed adding lib/portfolio.ts to the Governance Drift workflow's path filter. Checking before building showed that wouldn't work: check_governance_drift.py validates the vendored registry's internal consistency and its remote repo canaries. It has no knowledge of this repo's TypeScript unions. Running it on a portfolio change would have been a no-op that looked like a fix — arguably worse than nothing, since it would have closed the item.

What actually closes it

verifyGovernanceVocabularyParity() in scripts/verify-portfolio.ts — the verify:portfolio job already runs on every PR and can see both sides.

It asserts that the ProjectStatus and PublicStage unions in lib/portfolio.ts and the registered iids-portfolio vocabulary contain exactly the same codes. The unions are read from the exhaustive OPERATIONAL_LABEL / PUBLIC_STAGE_LABEL records, so tsc guarantees there's no third list to maintain. A missing vocabulary group is itself an error rather than a silently-skipped check.

Both directions fail:

Drift Why it matters
Code in the union, not in the vocabulary The registry misdescribes what statuses exist — the scoping case
Code in the vocabulary, not in the union A code was retired without deregistering it; the Data Model explorer shows stakeholders a state the site can no longer produce

Each message names the fix, including the two-repo order.

Verified against real drift, not just "it passes"

Reproduced the original failure by removing scoping from the generated vocabulary:

[ERROR ] iids-portfolio/ProjectStatus (tracked)
         "scoping" is in the ProjectStatus union in lib/portfolio.ts but not
         registered in the vendored vocabulary. Add it upstream in
         ui-insight/data-governance (vocabularies/iids-portfolio/allowed_values.json),
         bump the submodule, then re-run npm run build:governance.

And the reverse, by adding a code the union lacks:

[ERROR ] iids-portfolio/ProjectStatus (tracked)
         "mothballed" is registered in the vendored ProjectStatus vocabulary but is
         not a member of the union in lib/portfolio.ts. Either the code was retired
         without deregistering it upstream, or the submodule is ahead of this repo.

Baseline unchanged: 29 projects, 0 errors, 2 pre-existing stale-commit-date warnings. npm run build and npm run lint pass.

Docs

ADR 0001 gains an amendment closing both vocabulary follow-ups (paused was done in data-governance#15; scoping in #17) and recording the consequence: adding an operational status is now a two-repo change in a fixed order — vocabulary upstream, submodule bump, build:governance, then the union. It also notes that a "Follow-up" line whose only enforcement is someone remembering it isn't enforcement, which is the lesson the scoping gap actually taught.

Follows #318.

🤖 Generated with Claude Code

The `scoping` drift closed in #318 should never have been findable only
by hand. ADR 0001's amendment named the upstream registration as a
follow-up, the follow-up was missed, a project shipped claiming the
status, and every check stayed green for three days.

My first instinct was to add lib/portfolio.ts to the Governance Drift
workflow's path filter. That would not have worked: the drift script
validates the vendored registry's internal consistency and its remote
repo canaries, and has no knowledge of this repo's TypeScript unions.
Running it on a portfolio change would have been a no-op that looked
like a fix.

The check belongs in verify:portfolio, which already runs on every PR
and can see both sides. verifyGovernanceVocabularyParity() asserts that
the ProjectStatus and PublicStage unions in lib/portfolio.ts and the
registered iids-portfolio vocabulary contain exactly the same codes.
It reads the unions from the exhaustive OPERATIONAL_LABEL and
PUBLIC_STAGE_LABEL records, so tsc guarantees there is no third list to
keep in sync, and a missing vocabulary group is itself an error rather
than a silently-skipped check.

Both directions fail. A code in the union but not the vocabulary means
the registry misdescribes what statuses exist; a code in the vocabulary
but not the union means one was retired without deregistering it, and the
Data Model explorer shows stakeholders a state the site can no longer
produce. Each message names the fix, including the two-repo order.

Verified by reproducing the original drift — removing `scoping` from the
generated vocabulary fails with the intended error — and the reverse, by
adding a code the union lacks. Baseline still passes: 29 projects, 0
errors, 2 pre-existing stale-commit-date warnings.

ADR 0001 gains an amendment closing both vocabulary follow-ups and
recording the consequence for future ones: adding an operational status
is now a two-repo change in a fixed order, and an amendment that defers
something should say what will fail if it is forgotten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Vendored strategic-plan submodule is behind upstream

The vendored submodule pointer at vendor/strategic-plan is pinned to 434de6e, which was committed 117 day(s) ago (threshold: 14 days).

The submodule is pinned at upstream main HEAD, but that HEAD itself is older than the threshold. No action needed in this repo — upstream simply hasn't moved.

This is an advisory comment from strategic-plan-pr-summary.yml. It does not block the build. Threshold is configurable via the STALE_AFTER_DAYS workflow env var (currently 14). This comment is updated in place across pushes.

@ProfessorPolymorphic
ProfessorPolymorphic merged commit 6c923a2 into main Jul 27, 2026
7 checks passed
@ProfessorPolymorphic
ProfessorPolymorphic deleted the ci/verify-governance-vocab-parity branch July 27, 2026 13:21
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