Skip to content

feat: establish the Stage 1 safe core and the pnpm 11 repository foundation - #2

Merged
evk-soft merged 33 commits into
mainfrom
repository-foundation/f1
Aug 6, 2026
Merged

feat: establish the Stage 1 safe core and the pnpm 11 repository foundation#2
evk-soft merged 33 commits into
mainfrom
repository-foundation/f1

Conversation

@evk-soft

@evk-soft evk-soft commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Brings main up to the owner-approved Stage 1 Phase 1 and the repository foundation on pnpm 11.

This is a one-time catch-up: everything here predates main having CI worth requiring. From the
next pull request onward the rhythm is one gated phase, one small pull request.

What lands

Stage 1 Phase 1 — the safe core contracts (ec88ca3, tagged stage-1/phase-1)

@evk-soft/ai-tooling with strict I-JSON parsing, seven offline JSON Schema documents, RFC 8785
canonicalisation, deterministic generated-JSON rendering, a fail-closed phase-delta verifier, a
bounded tarball reader for the package boundary, and the instruction-only core pack. 76 files,
128 tests.

Repository foundation (9b4d455, tagged foundation/f1)

  • pnpm 10.28.0 -> 11.20.0; behavioural settings moved from .npmrc to pnpm-workspace.yaml
  • supply chain: an empty allowBuilds, so no dependency executes code at install time, and
    minimumReleaseAge so a freshly published version cannot be pulled in on the day it appears
  • catalogs single-source shared versions; the Biome version stops being written into 12 $schema
    URLs and survives only as a catalog entry
  • four guard scripts: dependency cycles, workspace boundary escapes, advisories, licences
  • post-checkout / post-merge hooks that exit early inside a linked worktree
  • CI: least-privilege token, SHA-pinned actions, and a Windows matrix leg
  • .editorconfig, ignore rules, turbo, changelog scaffolding, shared agent configuration

Verification

CI is green on windows-latest, ubuntu-latest and the Bun smoke job. Locally, against the
committed tree:

pnpm check                  128 tests, pack:check included   exit 0
check-circular              5 workspaces, no cycle
check-workspace-boundaries  37 source files, no escape
check-audit                 0 advisories
check-licenses              85 packages, 0 conflicts
check-stage1-artifacts      exit 0

Each phase changed exactly the paths in its committed manifest under
docs/superpowers/plans/manifests/, with exactly one commit and one parent. The foundation phase
left packages/ai-tooling and configs/ai byte-identical to the approved Phase 1 tree.

Note on history

Merging is squash, so the per-phase commits do not become ancestors of main. They stay reachable
through the annotated tags stage-1/phase-1 and foundation/f1, which is what
docs/superpowers/plans/PROGRESS.md refers to.

evk-soft and others added 30 commits August 1, 2026 21:20
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Owner baseline for Stage 1 execution, separate from any Stage 1 phase commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two literal snippets could not execute as written.

Packet 1B: the fixture manifest listed kept.txt before expected.txt, but the
Step 3 parseManifest literal rejects an unsorted manifest before any delta
comparison, so the test failed with 'manifest paths are duplicate or unsorted'
instead of the deletion message. Reordered to raw-byte order; scenario unchanged.

Packet 1A: vitest.config.ts used poolOptions.forks.singleFork, removed in the
pinned Vitest 4.1.10. The option was ignored, so the intended serial execution
did not apply. Replaced with top-level maxWorkers: 1, keeping isolate at its
default true rather than the migration guide's isolate: false, because Stage 1
tests create real temporary repositories and assert containment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Phase manifests do not list this file, so it is maintained on the plan branch
only and never edited inside a phase execution worktree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pnpm pack 10.28.0 rejects --ignore-scripts and --ignore-pnpmfile with 'Unknown
options'. Suppression is carried by npm_config_ignore_scripts and
npm_config_ignore_pnpmfile in the frozen environment, which pnpm honours.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Phase 1 creates deliberately invalid JSON fixtures, but the exclusion that lets
biome check parse the tree was assigned to Phase 3, so root pnpm check could not
pass from the moment those fixtures were committed. biome.json now appears in the
Phase 1 manifest (76 paths); Phase 3 keeps its own biome.json entry for the
formatter-boundary work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two separately gated phases for repository infrastructure, tracked apart
from the Stage 1 product work.

Corrects four points where the agreed design did not match the tree:

- .gitattributes already normalizes text to LF, so F1 extends it rather
  than creating it
- .npmrc already exists; pnpm 11 restricts it to registry and auth, so
  its three behavioural keys migrate to pnpm-workspace.yaml in camelCase
- onlyBuiltDependencies is replaced by allowBuilds in pnpm 11, so the
  pnpm upgrade moves into F1; authoring the settings twice is avoided
  and F2 is left carrying only the TypeScript 7 compiler risk
- check-audit.mjs and check-licenses.mjs do not exist in the reference
  project and are new work, not a port

Two probes back constraints that were otherwise assumptions:

- pnpm pack rejects a catalog: specifier outside a workspace, so
  catalogs must not reach packages/ai-tooling without breaking the
  Phase 1 pack:check gate
- git worktree add does fire post-checkout with $3=1, so the new hooks
  guard on git-dir vs git-common-dir rather than on $3

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ec88ca3 is approved exactly as committed. The deferred hostile fixtures
and the two type-level assertions were explicitly not required first, so
the commit is final and must not be amended.

Next action is the repository foundation track, not Phase 2. Records the
history fork at b3ec1b2 that must be linearized before that work starts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three independent auditors reviewed revision 1. Every finding relayed
here was re-verified directly against the tree before being accepted.

Removed one false claim: the Stage 1 artifact scanner does not declare a
dependency-license-conflict finding class. It emits exactly
private-marker, credential-pattern, schema-byte-mismatch,
unexpected-executable and undeclared-entry, and it walks only
packages/ai-tooling and configs/ai, so a root-level licence guard could
not feed it. The justification for check-licenses.mjs is rewritten.

Four blocking constraints revision 1 missed:

- .gitignore has no claude, turbo or idea entry, so committing .claude/
  and adding turbo would leave untracked paths that fail the phase
  manifest check on the first Phase 2 session
- phase plans carry literal executable pnpm commands, not prose:
  phase 3 line 4596 runs corepack install --global pnpm@10.28.0 and
  phase 1 line 60 throws unless pnpm is exactly 10.28.0, so the pnpm
  pin amendments must land inside F1's own commit
- no phase manifest lists changelog.d or CHANGELOG.md, so no Stage 1
  phase can author a fragment; the scaffolding is created dormant
- check-package-contents.mjs resolves the exact packageManager version
  from the corepack cache with the network disabled, so pnpm 11.20.0 is
  an F1 execution precondition; its regex also rejects the integrity
  hash form

Four overstated mechanisms corrected: catalogMode strict is an add-time
guard and does not forbid inline versions; pnpm check does widen its
lint input set even though the script definition is unchanged; the
lockfile format change was unverified and is withdrawn; allowBuilds is
documentation of intent rather than a switch that disables a live vector.

F2 grew: Biome is pinned in the $schema URL of 12 tracked files, and
configs/typescript-config declares a public peer range of
^5.9.3 || ^6.0.0 that no catalog can rewrite. Its risk is raised to
high because the reference project holds TypeScript at 6.x on the
record, naming the TS7 Go compiler as the reason.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four owner decisions, one of which removed a design defect rather than
just answering a question.

Biome version references. The version was written into the $schema URL
of 12 tracked files, which is 12 sync points for every upgrade forever.
Biome ships its schema inside the npm package and documents a relative
path as a supported alternative, verified to resolve from both the
repository root and configs/biome-config. F1 replaces all 12, so the
version survives only in the catalog entry and F2's Biome work collapses
to one line. $schema is an editor affordance that Biome never reads to
select behaviour, and the published peer range of @evk-soft/biome-config
is already ^2.3.11, so a URL naming one exact version was advertising
something narrower than the package accepts.

Runtime posture. Node.js is the default and only runtime the toolchain
and gates target. Bun is frozen, not removed: the smoke job never
invokes pnpm and is unaffected by the upgrade, while @evk-soft/runtime-detect
and @evk-soft/biome-config both declare engines.bun in published
manifests and the latter exports a ./presets/bun entry point. Dropping
Bun is a product decision about two published packages, not a
foundation change, and nothing new is coupled to it.

Agent configuration. .claude/settings.json is committed with an exact,
wildcard-free allowlist; every Claude Code runtime path is ignored.

CI. A Windows job is added, plus a step that finally runs the
packages/ai-tooling gate commands. macOS waits for Phase 3. The Bun job
is left untouched.

No open questions remain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two gated phases with closed manifests, one commit each, and an owner
stop, following the Stage 1 master plan section 0.3 protocol. 75 steps
across F1 (40 paths) and F2 (10 paths).

Both manifests were validated before the plan was written: byte-sorted,
grammar-clean, CR-free, duplicate-free, and against ec88ca3 every M path
exists while no A path does.

Also corrects the design. The audit finding that CI never invokes a
packages/ai-tooling gate command was read against the plan branch, where
Phase 1 does not exist. On F1's actual base the root check script already
chains check:ai-tooling, which expands to typecheck && test && pack:check,
so no new CI step is needed and the Windows job inherits the coverage.

Three defects found by self-review and fixed before commit:

- nine preset paths appeared in the F1 manifest but only in shorthand in
  the plan's Files block
- gate commands piped git output through -split on a value PowerShell
  already returns as string[], which would have joined the array with
  spaces and broken the manifest comparison
- approvedBaseSha was bound in the entry snapshot and consumed in the
  gate task with no instruction to retain the session

minimumReleaseAge is 4320 minutes rather than the reference project's
10080: turbo 2.10.8 was five days old when this plan was written, so a
seven-day delay would have blocked F1's own install.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
evk-soft and others added 3 commits August 6, 2026 15:07
Every finding relayed here was independently reproduced before being
accepted; three auditor claims were rejected as misreadings.

Six defects that would have broken execution:

- corepack use rewrites packageManager to the integrity-hash form,
  which check-package-contents.mjs rejects, and runs a scripts-enabled
  install that fires the husky prepare hook. Replaced with
  corepack prepare --activate plus an assertion on the field.
- @(git ...) | Where-Object returns a bare String when exactly one line
  matches, so $parents[0] indexed the character 'p'. The single-parent
  check in both phase gates could never pass on a correct commit.
- $LASTEXITCODE was read after Select-String, a cmdlet that never sets
  it, in two guards. Both would have thrown on a clean tree and stayed
  silent after a failed native command.
- check-audit.mjs spawned the bare name pnpm with shell:false, which is
  ENOENT on Windows where pnpm is a .CMD shim. Now runs pnpm's JS entry
  through Node via npm_execpath.
- check-licenses.mjs failed on the clean base tree: lightningcss ships
  under MPL-2.0 via vite under Vitest 4. Added with a written reason.
- the six scripts failed biome check on import ordering and one unused
  import, so pnpm check would have broken from task F1.5 onward. Import
  lists corrected and an explicit format step added.

Also: bounded the codemod blast radius; made F2 check Biome read-only
before letting it write into the approved tree; moved the boundary probe
out of packages/ai-tooling; used a depth-correct relative schema path for
the ten preset files; amended the biome.json body embedded at phase-3
line 4526, which would otherwise have reintroduced a versioned schema URL;
recorded two out-of-manifest pins as named exceptions; added the
allowBuilds behaviour confirmation the design requires.

Root package.json was removed from the F2 manifest. After F1 its
devDependencies read catalog:, so the F2 bump happens entirely in
pnpm-workspace.yaml and the file does not change. F2 is now 9 paths.

Verified against the real base tree: check-circular ok on 5 workspaces,
check-workspace-boundaries ok on 37 files, check-licenses ok on 84
packages, check-audit ok with 0 advisories.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three candidates from the reference project were considered for F1 and
kept out. Reasons recorded so the question is not reopened from scratch.

Documentation link checking is already product work: Stage 1 Phase 3
delivers `ai-tooling docs check-links`, backed by src/docs/link-checker.ts
and src/commands/docs.ts, both in the Phase 3 manifest. It validates
existence, exact filename case, anchors, images and escapes outside the
repository root. A scripts/check-docs-links.mjs would be a second and
weaker implementation competing with the product two phases later. The
follow-up is to wire the product command into pnpm check once Phase 3 is
approved, which is the self-hosting the Stage 1 design asks for.

Measured while deciding: devkit has zero unresolved relative doc links.
The six a naive scan reports sit inside a tilde-fenced json block in the
Phase 3 plan and are the link checker's own test vectors.

Documentation code-path checking cannot work while the docs are mostly
plans, which by definition name files that do not exist yet; a naive scan
reports 630 false positives. Release and version management serves a
workflow that does not exist: six packages at 0.1.0, nothing published,
publication a Stage 1 non-goal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Foundation phase F1. Changes exactly the 40 paths in
docs/superpowers/plans/manifests/repository-foundation-f1.txt and leaves
packages/ai-tooling and configs/ai byte-identical to the approved Stage 1
Phase 1 tree.

Ignore rules come first: .claude/ is denied by default and re-admits only
settings.json, rules/ and skills/, so any future Claude Code runtime path
is ignored without being enumerated. .turbo/ and .idea/ join it. Without
this the first Phase 2 session would fail its own manifest check.

pnpm 10.28.0 -> 11.20.0. The three behavioural settings move out of
.npmrc, which v11 reads for auth and registry only, into
pnpm-workspace.yaml in camelCase. allowBuilds is an empty allowlist and
minimumReleaseAge is 4320 minutes; both were chosen against measured
publish dates rather than copied, since a 7-day delay would have blocked
turbo 2.10.8 itself.

Catalogs single-source the shared versions but deliberately stop at the
packages/ai-tooling boundary: check-package-contents.mjs packs from a
staging root outside the workspace, where a catalog: specifier cannot
resolve.

The Biome version leaves the tree entirely. It was written into the
$schema URL of 12 files; all now point at the schema shipped inside the
installed package, so the version survives only as a catalog entry.

Four guard scripts, six package scripts, and two husky hooks. The hooks
exit early inside any linked worktree, because git worktree add really
does fire post-checkout and passes $3=1, so testing $3 alone does not
filter it.

CI gains a least-privilege permissions block, SHA-pinned actions and a
Windows leg. No step was added for the ai-tooling gate commands: check
already chains check:ai-tooling, which expands to typecheck && test &&
pack:check.

The 15 pnpm pins in the six Stage 1 plan documents are amended in this
same commit, because phase 3 carries a literal corepack install command
and phase 1 asserts an exact version; leaving them would downgrade the
toolchain mid-Stage-1.

Three deviations from the written plan, each verified:

- pnpm 11 aborts its first install asking to purge node_modules and
  cannot prompt without a TTY. Resolved by removing the directory
  explicitly rather than adding a confirmModulesPurge setting the plan
  never declared.
- the v10-to-v11 codemod was skipped deliberately. It is an unpinned
  package fetched outside the lockfile and minimumReleaseAge, and the
  migration is three settings. The plan permits this.
- both hooks use explicit `if` blocks rather than `[ ... ] && exit 0`.
  Husky runs hooks through sh -e, where an AND-list with a false left
  side yields status 1. Verified under sh -e, in a linked worktree, and
  in the main worktree on a real dependency change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@evk-soft evk-soft changed the title chore(repo): repository foundation on pnpm 11 (CI validation, not for merge) feat: establish the Stage 1 safe core and the pnpm 11 repository foundation Aug 6, 2026
@evk-soft
evk-soft marked this pull request as ready for review August 6, 2026 17:49
@evk-soft
evk-soft merged commit bb7ba9e into main Aug 6, 2026
6 checks passed
@evk-soft
evk-soft deleted the repository-foundation/f1 branch August 6, 2026 17:50
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