Skip to content

The stack manifest records where a copy came from, and stops calling a monorepo's test layout drift - #6

Merged
bodurkalukasz merged 2 commits into
mainfrom
fix/stack-provenance-and-the-vitest-entry
Sep 3, 2026
Merged

bodurkalukasz merged 2 commits into
mainfrom
fix/stack-provenance-and-the-vitest-entry

Conversation

@bodurkalukasz

@bodurkalukasz bodurkalukasz commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Closes #5 - both halves, and one of them by declining the fix the issue asked for. I filed
that issue from the adoption run; having implemented it, I think half of it was wrong, and the
reasoning is below rather than in a commit nobody reads.

1. provenanceCommit - implemented as asked

stack.manifest.json gains the field, shipping null. The run that applies or updates this
layer writes this repository's commit SHA into the adopter's copy.

The asymmetry it closes is visible the first time a real repository updates. The core half of
the delta is an exact diff between two commits, because standard.manifest.json records the
commit its copy came from (standard ADR-052). The stack half had "version": "0.3.1" and
nothing else, so the diff had to be reconstructed from the changelog. That matters more here
than it would in the core: most entries in this manifest are merge class and carry no
sha256, so an unrecorded base does not make the stack half coarse - it makes it
unenumerated. A release's additions can go unapplied to every merge entry while self-verify
still reports drift 0.

The field names a commit of this repository. A stack is linked to the core by a registry
pointer rather than a version range, so the two clocks are independent and neither commit is
derivable from the other.

ADAPTING.md says who writes it and when, since nothing in the core's skills knows about it
yet. If it would be better for update-to-latest to write it automatically, that is a core
change and I am happy to open it there - the field has to exist first either way.

2. vitest.config.ts becomes optional

Not "conditional on a profile", which is what the issue proposed. There is no axis in the
schema for it, altPaths takes literal paths rather than globs, and inventing a field the
core's self-verify.mjs does not read would ship metadata that looks like a check and is not.

What DECISIONS#9 asks for is the tier split. It does not ask for it at a path. In a workspace
where each package configures its own tiers, the decision is satisfied where the tests
actually run, and a root projects config on top of those runs every suite a second time - so
the root file there is wrong, not missing. Marked required, the entry produced drift for a
repository that had done nothing wrong, and the exception recording it sat in the same list as
the exceptions that mean something. That is the cost I care about: an exception that records a
schema limitation devalues the ones that record a real deviation.

Optional is an honest reading of a check this schema cannot make, and it is also weaker - a
repository with no tiers anywhere now passes the same way. The expressiveness belongs to the
core (the manifest schema and scripts/self-verify.mjs), so SELF-11 files the request
rather than papering over it here; if the core learns to say "this path, or one per workspace
package", the entry goes back to required with that spelling.

3. biome.json stays required - declining my own issue

The issue asked for the same treatment. It should not have.

ADAPTING.md prescribes a two-step Biome migration and warns against a big-bang swap, so a
repository following this stack's own advice correctly has no biome.json between the steps.
That is not a decision satisfied elsewhere - it is DECISIONS#3 not yet taken, and the drift
number is the only place it is visible. Optional would let a repository that will never
migrate read as finished.

What was actually wrong was that the state between the two steps had no documented shape. So
ADAPTING.md now gives the exception to record, with the migration step in the reason, and
says it comes out when step 2 lands:

{ "kind": "file", "match": "biome.json", "reason": "ESLint + Prettier; Biome migration step 1 of 2, see ADAPTING.md" }

SHIPPED.md states the same thing once for every entry: required is what the verifier
counts, not a demand for today.

Also in here

One word in the manifest's $about: (core ADR-022) reads (standard ADR-022), the spelling
core 1.0.11 adopted for shipped files after #133. This file ships into repositories that have
their own ADR index, which is exactly the case that issue was about. Revert it if this repo
would rather stay on core ADR-NNN until it updates - README.md still uses that form.

Verification

  • node scripts/self-verify.mjs - drift 0, 97% (88/91), unchanged from main.
  • node scripts/spec-structure.mjs - OK, 10 spec paths.
  • node scripts/spec-guard.mjs --base origin/main --block - OK. Both touched capabilities
    (stack-contract, adoption-path) carry the behaviour change in their specs: a data
    contract row, two core concepts, two rules and two acceptance criteria.
  • node scripts/decision-records-check.mjs - OK.
  • stack.manifest.json parses.

No version bump and no version heading: the changelog entry sits under ## Unreleased for the
maintainer to cut.

Second commit: what the first one left stale

Self-review of my own diff, in the three places it left inconsistent.

  • This repository's standard.manifest.json waived vitest.config.ts with a kind: file
    exception, because the entry was required and this repository publishes the stack rather
    than consuming it. Optional now, so the exception waives nothing - it cannot be the
    difference between drift and no drift. That is the exact cost argued about above, so it is
    deleted.
  • The stack-contract spec's open question said four entries fail and named
    vitest.config.ts among them. Three do. It is the evidence behind a question somebody has
    to decide, so the number stays measured.
  • The $about ended up citing three core records in two spellings. One paragraph, one
    spelling: all three read standard ADR-NNN.

Guards re-run after it: self-verify drift 0 (88/91, 3 excepted), spec-structure OK, spec-guard
OK, decision-records OK. CI on the branch: spec-guard, gitleaks and starter-boot all green.

… counting a monorepo's test config as drift

Closes #5, both halves, one of them by declining the fix the issue proposed.

`stack.manifest.json` gains `provenanceCommit`, shipping `null`, written into the adopting
repository's copy by the run that applies or updates this layer. The core's manifest has
carried the equivalent since standard ADR-052, and the asymmetry showed the first time a real
repository updated: the core half of the delta is an exact diff between two commits, the stack
half had a version string. Most entries here are `merge` class and carry no hash, so that half
was not coarse - it was unenumerated, and a release's additions could go unapplied with the
drift number still reading zero. The field records a commit of THIS repository: the layers are
linked by a registry pointer rather than a version range, so neither commit follows from the
other.

`vitest.config.ts` becomes optional. What DECISIONS#9 asks for is the tier split, not a path.
A workspace whose packages each configure the tiers has them where the tests run, and a root
projects config on top of those runs every suite twice - so for that shape the root file is
wrong rather than missing. Required, the entry manufactured drift for a repository that had
done nothing wrong, and the exception recording it sat beside the exceptions that mean
something. What the schema cannot say - this path, or one per workspace package - is the
core's expressiveness to extend, and `altPaths` takes literal paths rather than globs; filed
as SELF-11 instead of worked around here.

`biome.json` stays required, against what the issue asked for. The adaptation path prescribes
a two-step Biome migration, so a repository following it correctly has no `biome.json` between
the steps - and that is a real, unfinished deviation from DECISIONS#3 which should read as one.
Making the entry optional would let a repository that will never migrate look finished.
`ADAPTING.md` now gives the exception to record, with the migration step in its reason, and
says it comes out when step 2 lands. That is the difference between the two entries: one
decision is satisfied elsewhere, the other is not yet taken.

`SHIPPED.md` says what "required" means for a repository mid-migration, since that is where
the word was being read as a demand rather than as what the verifier counts. The manifest's
own `$about` cites the core's records as `standard ADR-NNN`, the spelling core 1.0.11 adopted
for shipped files after issue #133 - this file ships into repositories that have their own
index.
…, and keep the count measured

Self-review of the previous commit, in the three places it left behind.

This repository's own `standard.manifest.json` waived `vitest.config.ts` with a `kind: file`
exception, because the entry was required and this repository publishes the stack rather than
consuming it. The entry is optional now, so the exception waives nothing: it cannot be the
difference between drift and no drift, and it sits in the list that is supposed to mean
something. That is the exact cost the previous commit argued about, so it goes.

The `stack-contract` spec's open question said four entries fail and named `vitest.config.ts`
among them. Three do. A measured claim that quietly stops being measured is worse than no
number, and this one is the evidence behind an open question somebody has to decide.

The manifest's `$about` cited three core records in two spellings after the previous commit -
`ADR-016 in the core repo` beside `standard ADR-022`. One paragraph, one spelling: all three
now read `standard ADR-NNN`, which is what core 1.0.11 settled on for files that ship into a
repository with its own index.
@bodurkalukasz
bodurkalukasz merged commit 8f7e651 into main Sep 3, 2026
3 checks passed
@bodurkalukasz
bodurkalukasz deleted the fix/stack-provenance-and-the-vitest-entry branch September 3, 2026 21:12
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.

stack.manifest.json has no provenanceCommit, and biome.json / vitest.config.ts land unconditionally

1 participant