Add socketRisk (9th filter result) and lastRevalidated (nullable ISO date)
to the library-decision trace schema. Downstream enforcement layers
(evaluate-library skill, check.mjs major-bump mode, revalidate.mjs cron)
all depend on these fields being validated at the schema layer first.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Decomposer produced 9 stories under docs/work/2026-05-14-ci-
security-and-supply-chain/, ordered to land the schema foundation
first and the cross-referencing content (reviewer prompt, guide)
last:
01 - trace schema extensions (socketRisk + lastRevalidated)
02 - Socket integration (skill + CI)
03 - Renovate adoption
04 - major-bump re-evaluation flow
05 - trace revalidation workflow
06 - CodeQL + audit signatures
07 - gitleaks pre-commit
08 - reviewer prompt update
09 - CI security guide + docs
Also fixes a one-char status typo in the PRD frontmatter
(\`appoved\` -> \`approved\`) that landed with the decompose run.
Anchored by ADR-023 + the approved PRD at
docs/work/prds/2026-05-14-ci-security-and-supply-chain.prd.md.
Sequencing: depends on stories 01/02/04/06 of the in-flight
library-evaluation epic landing first.
- ADR-023 codifies the four-pillar enforcement stack: Renovate for
bumps + Action SHA pinning via pinGitHubActionDigests, Socket.dev
as a 9th hard filter in evaluate-library (free App + self-hosted
socket-cli + reviewer-prompt enforcement), weekly trace
revalidation cron with two-tier divergence action (rolling
dashboard issue + per-dep re-evaluation issues), and the baseline
GitHub-native gates (CodeQL, pnpm audit signatures, gitleaks
pre-commit + native push protection). Failure-mode hierarchy is
the single source of truth referenced by the sandcastle reviewer.
- Section 6 amends ADR-022 in place: major-bump re-evaluation
trigger (minor/patch bumps skip), last-revalidated frontmatter
field (preserves original date for adoption provenance), and
Socket as the 9th hard filter. ADR-022 stays unedited; both ADRs
read as a composed policy.
- PRD at docs/work/prds/2026-05-14-ci-security-and-supply-chain.prd.md
seeds the implementation epic; explicit sequencing -- depends on
the in-flight library-evaluation epic's stories 01/02/04/06
landing first.
- Glossary gains "Trace revalidation" + "Major-bump re-evaluation"
entries referenced by both ADRs.
Catalyst: 2026-05-14 audit confirmed zero security tooling in the
repo + GitHub Actions pinned to major-version tags (the tj-actions/
changed-files attack class). ADR-022 closes the adoption-time gate;
ADR-023 closes the post-adoption drift gate.
Add approved trace files for payload, @trpc/server, @trpc/client, zod,
superjson, @payloadcms/db-postgres, @payloadcms/richtext-lexical, globals,
react, react-dom, vitest, @tanstack/react-query, and all @testing-library/*
packages. All traces dated 2026-05-14, decision: approved, adr: null.
Establishes the baseline so the pre-commit library-decisions gate is
additive (new deps require traces) rather than disruptive (old deps fail
immediately). All 34 trace files pass validateTrace() from schema.mjs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds approved trace files dated 2026-05-14 for all 13 OpenTelemetry
packages in packages/core-shared and packages/core-audit:
@opentelemetry/api, api-logs, context-async-hooks,
instrumentation, instrumentation-http, instrumentation-pg,
instrumentation-undici, resources, sdk-logs, sdk-metrics,
sdk-node, sdk-trace-base, semantic-conventions
All files pass validateTrace() from schema.mjs. The @sentry/opentelemetry
bridge was already covered in the ADR-014 cluster commit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Approved traces for @sentry/nextjs, @sentry/opentelemetry,
@sentry/node, and @sentry/react — all at ^10.51.0 in
packages/core-shared. Without these files the pre-commit
library-trace hook would fire retroactively on any future
package.json touch; backfill establishes the baseline.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add approved trace files for inversify ^6.2.0 and reflect-metadata
^0.2.2, both mandated by ADR-002 (InversifyJS for DI) and used across
all five feature packages. Both pass validateTrace() from schema.mjs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Translates ADR-022 from decision-record density into an onboarding
narrative: why the policy exists, the tier trigger, the four enforcement
layers, a step-by-step walkthrough, and worked approved/rejected examples
(clsx pass, trpc-to-openapi named-consumer fail).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates the shared schema module for library evaluation traces
(ADR-022 §4): Zod-validated frontmatter with all 8 filter fields and
enum constraints, plus parseTrace/validateTrace exports and a custom
YAML frontmatter parser for the nested trace format.
Also adds docs/library-decisions/_template.md with all 11 required
headings (8 Filter + 3 Prompt) in machine-checkable ADR-022 order.
Adds zod as a root devDependency so the script is runnable directly
from the workspace root without a package context.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ADR-022 codifies the tiered library-evaluation policy: 8 hard
auto-reject filters (license, types, maintenance, boundary-fit,
shadow-check, EU residency, CVE scan, named consumer), 3
discussion prompts, per-decision trace artifact at
docs/library-decisions/, and a 4-layer enforcement stack
(Claude PreToolUse/PostToolUse hook -> evaluate-library skill ->
pre-commit hook -> sandcastle reviewer prompt). Mirrors the
conformance-system latency pattern from ADR-012.
- PRD at docs/work/prds/2026-05-14-library-evaluation-policy.prd.md
seeds the implementation epic; status: approved, ready for
\`pnpm work decompose\`.
- Glossary gains "Library trace" + "Pre-shipped trace" entries
referenced by both artifacts.
Catalyst: the 2026-05-14 grill session nearly adopted
trpc-to-openapi + zod-to-json-schema before someone asked who the
HTTP consumer was. Honest answer: none -- all callers are TS via
createCaller. This policy makes that question structurally
unavoidable for any future feature- or core-tier dep.
Catches up the story's checkbox + frontmatter status to reflect that
the slice shipped in commit 1bbe866. The V1 orchestrator landed the
implementer's slice commit on main but had no state-mutation step,
so the bullet stayed unticked and `pnpm work next` would have
redundantly re-dispatched the implementer for a no-op slice.
Bookkeeping-only — no code changes.
Re-decomposes the approved binder-wrap-helper PRD after the previous
8-story attempt (dropped in 71c04f5) sliced horizontally — its
"write test" / "write impl" splits would have left intermediate
commits red. The new shape obeys slice = task = PR = commit:
- 01-wire-use-case-helper — 1 task: ship the wireUseCase helper
(factory composition + container bind + brand stack) with its
unit tests and barrel export in one green commit. Blocks 02 + 03.
- 02-migrate-feature-binders — 5 tasks, one per feature
(auth, blog, media, marketing-pages, navigation). Each task
migrates that feature's bind-production.ts + bind-dev-seed.ts
together and keeps all gates green.
- 03-update-generator-templates — 1 task: update the feature
generator's bind-*.hbs so future scaffolds emit wireUseCase
directly instead of inline withSpan + withCapture.
Output of the now-fixed sandcastle decompose dispatch — depends on
the completionSignal + maxIterations wiring (eadbb7e, 26aa97f).
The stories were decomposed by the previous (unconstrained)
decomposer prompt — their Tasks lists were horizontal sub-steps
(read file → write impl → write test → export → run gates) instead
of the slice = task = PR = commit rule now enforced in fd8265c.
Removing the folder clears the way for a fresh `pnpm work
decompose 2026-05-13-binder-wrap-helper --execute` run under the
updated prompt. The PRD itself (status: approved) is unchanged.
Output from `pnpm work decompose 2026-05-13-binder-wrap-helper
--execute` — sandcastle ran the decomposer agent with subscription
auth (after the macOS keychain workaround + Dockerfile fix from
prior commits). The agent wrote files but hit `Max iterations: 1`
before committing, so this commit carries its output unchanged.
Epic: docs/work/binder-wrap-helper/
- _epic.md links to PRD 2026-05-13-binder-wrap-helper
- features: [core-shared, auth, blog, media, marketing-pages,
navigation, tooling]
Stories (8 total, with dependency edges):
01-wire-use-case-helper prereq (blocks 02..07)
Goal: helper at core-shared/conformance/wire-use-case.ts +
tests covering brand stacking, span/capture/audit composition,
idempotent bind. depends-on: [], blocks 02..07.
02-migrate-auth-binders depends-on [01]
03-migrate-blog-binders depends-on [01]
04-migrate-media-binders depends-on [01]
05-migrate-marketing-pages- depends-on [01]
binders
06-migrate-navigation-binders depends-on [01]
07-update-feature-generator depends-on [01]
08-holistic-validation depends-on [02..07], blocks: []
Final gate suite + fallow dupes check to verify the 5 binder-
pair clone groups have disappeared.
After 01 lands, stories 02..07 are parallelisable; 08 collects them.
Pre-commit hook regenerates _state.json + re-stages it so `pnpm
work next` immediately surfaces the new ready story.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two separate sandbox blockers surfaced when the user tried
`pnpm work decompose --execute`:
1. **Container died on exec** — our Dockerfile had:
- WORKDIR /workspace + CMD ["bash"]
- No `agent` user (sandcastle exec's as UID:GID it built with)
- node:22-bookworm-slim (missing some build deps the install
script wants)
Sandcastle expects:
- A non-root `agent` user with home at /home/agent (sandcastle
does `git config --global --add safe.directory /home/agent/workspace`,
which fails if the user doesn't exist or the container exited)
- ENTRYPOINT ["sleep", "infinity"] so the container survives
the gap between sandcastle creating it and exec'ing in
Replaced .sandcastle/Dockerfile with the shape `sandcastle init`
would generate (verified against
node_modules/@ai-hero/sandcastle/dist/InitService.js):
- node:22-bookworm (full, not slim) for build tooling
- apt-get installs git + curl + jq
- corepack-pinned pnpm@9
- ARG AGENT_UID=1000 + AGENT_GID=1000; sandcastle's
build-image passes the host's UID/GID by default
- `groupmod -o -g $AGENT_GID node` + `usermod -o ... node` —
the `-o` (non-unique) flag is required because macOS hosts
have UID:501 GID:20, and GID 20 collides with Debian's
`dialout` group in the base image (without -o, groupmod
fails with "GID '20' already exists")
- USER ${AGENT_UID}:${AGENT_GID}, then install Claude Code CLI
via the official installer
- ENV PATH includes /home/agent/.local/bin
- WORKDIR /home/agent (sandcastle overrides per-run anyway)
- ENTRYPOINT ["sleep", "infinity"] keeps the container alive
2. **"Not logged in · Please run /login"** inside the container —
Claude Code on macOS stores credentials in the Keychain, NOT in
~/.claude/.credentials.json. Sandcastle's bind-mount of ~/.claude
finds nothing usable. Documented the workaround:
- README.md "Sandcastle setup (one-time)" — macOS-specific
block with the `security find-generic-password ... > ~/.claude/.credentials.json`
one-liner + chmod 600 + the security trade-off (plaintext
file vs keychain isolation)
- docs/guides/runbook.md "Using Sandcastle → Prerequisites" —
step 3 (Authentication) gets a "macOS quirk" subsection with
the same extraction one-liner + the API-key fallback as the
alternative path
- scripts/work/{dispatch,decompose}.mjs — when the sandcastle
error matches /Not logged in|Please run \/login/ AND we're on
darwin, the dispatcher prints the keychain-extraction
commands + the API-key fallback inline above the generic
"See runbook" line, so future agents discover the fix at the
failure site
The image rebuilds clean (`pnpm exec sandcastle docker
build-image`) at ~1.95GB and the container survives sandcastle's
exec — confirmed by reaching the "Not logged in" stage (which is
the next-layer issue, not the Dockerfile issue).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the gap the user hit running `pnpm work decompose --execute`:
sandcastle errored with `Image 'sandcastle:template-vertical' not
found locally. Build it first with 'sandcastle docker build-image'`,
but neither the README nor the runbook documented this step.
README.md: new "Sandcastle setup (one-time)" section after Quick
reference. Three commands (docker info, build-image, auth) — the
minimum needed to make dispatch work. Links to the runbook for the
full lifecycle.
docs/guides/runbook.md: Prerequisites in "Using Sandcastle" grow
from 4 to 5 items. New step 2 walks through `sandcastle docker
build-image`, quotes the exact "Image not found locally" error so
agents searching for the string land on the fix, and shows the
remove-image + rebuild flow for Dockerfile edits.
.sandcastle/README.md: new "Build the sandbox image (one-time)"
section parallel to the env section, cross-linking to the runbook.
scripts/work/decompose.mjs + scripts/work/dispatch.mjs: when the
sandcastle error message matches the "Image '.+' not found locally"
pattern, the dispatcher now prints the build-image command inline
above the generic "See runbook" line. The error stack itself remains
unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Materialises the output of the improve-codebase-architecture skill's
grilling loop on Candidate 1 (binder duplication), sub-shape (a)
(helper-inside-binder).
Captured decisions:
- New wireUseCase helper at @repo/core-shared/conformance/
- Composes the existing withSpan + withCapture (+ optional
withAudit) wrappers; doesn't replace them
- Per-feature binders shrink to decision content + N wireUseCase
calls instead of N x ~12 lines of inline wrapping
- All 5 features migrated (10 binder files, ~24 inline wrap sites)
- Brand attachment stays in the existing wrappers
- Generator template emits the new shape so future scaffolds
don't regress
Sub-shape (b) (pre-wired factory exports) explicitly rejected in
favour of (a) — keeps the wrapping a binder concern, preserves
ADR-008's per-feature DI isolation.
Status: draft. Will not pass through pnpm work decompose until a
human reviewer flips status to approved. Expected to land as one
mid-sized epic with the helper + per-feature migrations as separate
stories.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adapts mattpocock/skills/engineering/improve-codebase-architecture to
this repo. Four files at .claude/skills/improve-codebase-architecture/:
SKILL.md (104 lines):
- Explore -> Present candidates -> Grilling loop process
- "Hard constraints (do not propose violations)" section
enumerating ADRs 006/008/010/012/013/014/015/017/020/021 that
bound the design space
- Repointed at docs/glossary.md (not CONTEXT.md) and
docs/decisions/ (not docs/adr/)
- Exploration shortcuts specific to this repo: pnpm fallow,
pnpm coverage:diff, feature.manifest.ts, pnpm turbo boundaries
- Grilling loop side-effects target the right glossary section
and the next available ADR number (currently 022)
DEEPENING.md (93 lines):
- 4 dependency categories mapped to this repo's reality:
Cat 1 (in-process) -> entities/use-cases/presenters
Cat 2 (local-substitutable) -> our existing real + mock
adapter pattern (every port has both; mocks ARE stand-ins)
Cat 3 (remote but owned) -> cross-feature events via
IEventBus (E0/E1 rules)
Cat 4 (true external) -> Payload, Sentry/OTel, socket.io
(each constrained to its vendor-isolation seam by ADR)
- Seam discipline section recognises DI symbols + manifest entries
as concrete seams alongside .interface.ts files
- Testing strategy: replace not layer (matches ADR-020 L0 + L1)
- Conformance check command list at the end (typecheck, lint,
test --coverage, conformance, fallow:audit, coverage:diff)
INTERFACE-DESIGN.md (66 lines):
- Parallel sub-agent "Design It Twice" pattern preserved
- Every sub-agent brief MUST include glossary terms + ADR
constraints + manifest awareness
- Output items extended with "Manifest + binder impact" and
"ADR conflicts (if any)"
- Comparison axes include conformance impact + coverage delta
- Cross-feature moves flag release-please version-bump
implications (per ADR-021 commit-path targeting)
LANGUAGE.md (79 lines):
- Matt's 7 abstract terms preserved (module, interface,
implementation, depth, seam, adapter, leverage, locality)
- New "Mapping to this repo's identifiers" table — abstract
term -> concrete file shape (e.g. seam -> *.interface.ts +
DI symbol + manifest entry + <gen:*> anchor)
- Rejected framings extended with our reserved meanings
("boundary" stays the ESLint workspace-tag term; "service"
stays the DI port term)
Per user follow-up: vocabulary anchored so that "module" defaults
to "feature" in this repo (since features are our primary unit of
organisation). Abstract refactor sense survives only when the cross-
scale abstraction is the point. Glossary.md updated:
- "Feature" entry adds the "module = feature in refactor sense"
cross-link
- New "Architecture refactor vocabulary" section with 9 terms
(Module, Interface (refactor sense), Implementation, Depth,
Seam, Adapter, Leverage, Locality, Deletion test, Deepening)
— all framed so feature is the primary instance
- Flagged ambiguities entry for "module" rewritten to capture the
three coexisting senses (workspace package / Node ESM / refactor
vocabulary defaulting to feature); new entries for "seam" and
"adapter" to prevent drift with the existing "boundary" / "service"
/ "scope" reservations
Hooks updated:
- session-start.sh skills line lists the new skill
- prompt-context.sh adds a 10th keyword group firing on
refactor / deepening / shallow / architecture / seam / adapter /
interface design / design it twice — inject points at SKILL.md
+ summarises the vocabulary and hard constraints
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the user's ask: versioning + a changelog generated on merging
to main, building on the just-mandated Conventional Commits substrate
(CLAUDE.md Key Conventions).
Architecture: ADR-021. Cookbook: docs/guides/releasing.md.
Initial state — six tracked packages at v0.1.0:
- . -> template-vertical (tag: template-v...)
- packages/auth -> @repo/auth (tag: auth-v...)
- packages/blog -> @repo/blog (tag: blog-v...)
- packages/media -> @repo/media (tag: media-v...)
- packages/marketing-pages -> @repo/marketing-pages (tag: marketing-pages-v...)
- packages/navigation -> @repo/navigation (tag: navigation-v...)
Core packages, tooling, and apps are NOT independently versioned
(ADR-021 rationale: core bumps cascade; apps aren't consumables;
surfacing them would create noise without information).
Configuration:
- release-please-config.json - 6 tracked packages, hybrid scope,
pre-1.0 conservative bump policy
(feat: -> patch, feat!: -> minor),
conventional-commit type mapping
- .release-please-manifest.json - baseline 0.1.0 for all 6 packages
- .github/workflows/release-please.yml - googleapis/release-please-
action@v4 on push to main,
concurrency-gated, write
permissions for the rolling PR
Workflow: on every push to main, release-please scans commits since
the last release tag PER PACKAGE (using commit-path, not the
conventional-commit scope), updates a single rolling release PR with
version bumps + per-package CHANGELOG entries. Merging that PR cuts
per-package tags + GitHub releases.
CHANGELOG files seeded at v0.1.0 baseline:
- CHANGELOG.md (root)
- packages/<feature>/CHANGELOG.md (5 features)
Subsequent versions are appended by release-please from commit
history. Do not edit manually.
Visibility surfaces updated (every agent entry point):
- CLAUDE.md Read First + new "Versioning is hybrid" Key Conventions
bullet (with bump policy summary)
- AGENTS.md preamble - new "Releases:" callout alongside Commits
- docs/glossary.md - new Releasing section with 8 terms (Conventional
Commits, release-please, Hybrid versioning, Tag prefix, Rolling
release PR, Bump targeting, Pre-1.0 bump policy, Release-As trailer,
CHANGELOG.md)
- docs/README.md - guides tree updated with releasing.md
- .claude/hooks/session-start.sh - one-line release reminder
- .claude/hooks/prompt-context.sh - new keyword group for
release/version/bump/semver/tag prompts
Package.json version bumps:
- root: name "template" -> "template-vertical", version "0.1.0"
- packages/auth, blog, media, marketing-pages, navigation: "0.0.0" -> "0.1.0"
Root rename rationale: release-please tags use the package-name + the
component prefix; "template-vertical" matches the repo identity (and
the user's question preview).
First release-please PR after this lands will sweep all subsequent
post-baseline commits into 0.1.1 / 0.2.0 bumps as appropriate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The docs/ tree had no index — a fresh visitor landing at /docs/
through GitHub's file browser would see just a glossary.md and four
subdirectories with no orientation.
docs/README.md gives:
- Where to start (CLAUDE.md + AGENTS.md links + glossary.md as the
"resolve a term" entry point)
- The full directory tree annotated with what each path holds
- Doc-type table (Glossary / Architecture / ADR / Guide / PRD /
Epic-Story-Task) with lifetime expectations
- "When to put what where" routing rules (new decisions -> ADR,
new how-to -> guide, new term -> glossary, new initiative ->
PRD, new diagram -> architecture/<name>-explainer.html)
- Conventions section codifying the rules already followed
implicitly across the existing docs
No content is duplicated — every section either lists or routes to
existing files. Adds the missing navigation surface so the docs/
tree is discoverable from any entry point.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the last two staleness threads from the docs audit:
1. data-flow-explainer.html had four "Plan-9" / "post-Plan-9"
references in the masthead, lede, fix-up bullet, and bindDevSeed
blurb. Stripped — the architecture is now just "vertical-feature".
No content changes beyond the noun rename.
2. audit-and-compliance-explainer.html had a footer link to
../superpowers/specs/2026-05-11-audit-and-compliance-design.md
(archived to .archive/ earlier). Replaced with a link to
ADR-018, which is the durable design record.
3. data-flow-explainer.html + di-explainer.html were inter-linked
with audit + conformance explainers, but had no markdown entry
point — they were orphans from any guide or architecture doc.
architecture/overview.md gains a new "Interactive explainers"
section listing all four single-file HTML walkthroughs with one
sentence each, so they're discoverable from the documented
entry point. The four pages already cross-link to each other.
Final state (verified by repo-wide grep): zero "Plan-N" / "Phase-N"
/ "docs/superpowers/" references in docs/ (excluding .archive/ which
is gitignored). Legitimate `superpowers:brainstorming` skill refs
in agent-first-workflow-and-conformance.md are preserved — those
reference an external plugin, not a repo path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>