Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# .dockerignore — build-context hygiene for the OpenCodeHub image.
#
# Mirrors .gitignore intent plus extra trimming: the builder stage runs a clean
# `pnpm install --frozen-lockfile` inside the image, so any host-side install
# artifacts, scratch state, and heavyweight test fixtures must NOT enter the
# build context (they bloat the context tarball and can shadow the in-image
# install). Keep this aligned with .gitignore when that file changes.

# --- Installed deps: re-installed fresh in the builder stage (AC-D8) ---
node_modules/
packages/*/node_modules/
.pnpm-store/

# --- Build outputs: rebuilt in the image; never copy host dist/ in ---
#
# CRITICAL: TypeScript `tsc -b` writes a per-package incremental cache at
# packages/<pkg>/tsconfig.tsbuildinfo. Docker's .dockerignore matches by PATH,
# so a bare `*.tsbuildinfo` only catches the context root — the nested
# per-package ones would still be copied in by `COPY . .`. A stale host
# tsbuildinfo makes the in-image `tsc -b` think a composite project is already
# built, emit ZERO output, and leave dependents unable to resolve
# `@opencodehub/<pkg>` (`TS2307`). The `**/` globs below exclude these at EVERY
# depth so the image always does a true clean build. (Same staleness trap as
# the project-references tsbuildinfo lesson.)
dist/
dist-test/
**/dist/
**/dist-test/
packages/*/dist/
packages/*/dist-test/
.tsbuildinfo
*.tsbuildinfo
**/*.tsbuildinfo
.astro/

# --- VCS + agent/planning scratch space (AC-D8) ---
.git/
.gitignore
.github/
.erpaval/
.handoff/
.claude/
.codehub/

# --- Sibling worktrees + local agent scratch (AC-D8) ---
.worktrees/
worktrees/

# --- Test fixtures rendered/checked-in for the suite (AC-D8) ---
#
# Only the runtime-rendered example fixtures under examples/fixtures/ are
# excluded — they are heavyweight sample repos consumed by the test suite, are
# never part of the TypeScript compilation unit, and are not needed at runtime.
#
# Do NOT exclude in-`src` `__fixtures__/` directories or per-package
# `test*/fixtures/`: several packages compile their tests as part of `tsc -b`
# (e.g. analysis/tsconfig includes `test/**/*` and src co-located tests import
# `src/group/__fixtures__/two-repo-contracts.ts`). Stripping those from the
# build context breaks the in-image workspace build with `TS2307`. The pruned
# `pnpm deploy --prod` closure already drops all test code from the RUNTIME
# stage, so excluding them from the build context buys nothing and only risks
# breaking the build.
examples/fixtures/

# --- Python eval venv + caches (not part of the JS runtime image) ---
.venv/
__pycache__/
*.pyc
*.egg-info/
.pytest_cache/
.ruff_cache/

# --- Local env / editor / OS noise ---
.env
.env.local
mise.local.toml
*.log
.DS_Store
coverage/

# --- Release / SBOM artifacts (regenerated; never baked into the image) ---
SBOM.cdx.json

# --- Docker's own files: no need to send them into the context ---
Dockerfile
.dockerignore
1 change: 1 addition & 0 deletions .erpaval/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ SARIF 2.1.0 ingestion + baseline diff + `codehub verdict` CI exit codes + `ci-in
- Hosted review UI (GitHub Checks + PR comments only)
- IDE plugin / LSP
- Model fine-tuning
- Single self-contained binary (pkg / SEA / Bun / Deno compile) — Docker image is the sole non-npm distribution artifact.

## Rip-and-replace latitude

Expand Down
207 changes: 207 additions & 0 deletions .erpaval/brainstorms/014-scip-lsp-packaging-determinism-plans.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: Quarantine nondeterministic extraction facts in a packHash-excluded sidecar
track: knowledge
category: architecture-patterns
severity: info
tags: [determinism, packHash, lsp, tier, sidecar, provenance, quarantine, adr-0019, adr-0005, erpaval]
modules: [packages/lsp-tier, packages/pack, packages/core-types]
discovered: session-893add (2026-06-19)
---

# Pattern

When you must add a lower-trust, inherently nondeterministic extraction source (here: LSP-server output for SCIP-blind languages — Swift/Zig/Elixir/Terraform/Clojure — via the vendored agent-lsp `workspace/symbol` + `blast_radius` logic) to a system whose value rests on a byte-identical reproducibility contract (`packHash`), DO NOT fold the new facts into the hashed manifest. Quarantine them:

1. **Separate sidecar, outside the hash preimage.** LSP facts live in `lsp-tier.sidecar.json`, NOT in `manifest.files[]`. `manifest.ts` (the hash input) is left 0-diff untouched. Result: `packHash` is byte-identical with vs without Tier-3 present — proven by a test that runs the real `buildManifest` both ways and asserts equality (`quarantine.test.ts` → "U2 QUARANTINE: packHash is byte-identical with vs without Tier-3 facts").
2. **Distinct, disjoint provenance tier.** A new `LSP_PROVENANCE_PREFIXES = ["lsp:"]` in core-types, pairwise-disjoint from `SCIP_PROVENANCE_PREFIXES` (first-party) and `SCIP_UNOFFICIAL_PROVENANCE_PREFIXES` (Tier 1.5). Every fact tagged `source=lsp`, `server=<binary>@<pinned-version>`. A consumer can always tell a compiler-grade edge from a heuristic one.
3. **Canonical re-sort at the boundary.** LSP output is unordered and server-version-sensitive; re-sort every collection to a stable key before any consumer reads it (the sidecar has its OWN byte-stability contract, separate from packHash).
4. **Opt-in + hard-fail.** Spawning the lower-trust source is opt-in (no opt-in → zero spawns, silent degrade to the existing tier). A partial/timeout result is a HARD failure, never cached.
5. **License the wrapped subprocess separately.** When vendoring a wrapper (agent-lsp MIT) that shells out to third-party servers (jdtls EPL, clangd/elixir-ls Apache), the WRAPPED server's license governs the subprocess — audit each one; the wrapper's permissive license does not launder them.

# Why

It lets you EXTEND breadth (a recurring product pull) without eroding the one uncontested moat (deterministic, reproducible packing). The determinism contract stays provably intact; the new capability rides alongside at a clearly-labeled lower confidence tier. Formalized in ADR 0019, which AMENDS rather than reverses ADR 0005 (0005 rejected LSP as the primary ORACLE; 0019 admits it as a labeled, batch-only, packHash-quarantined FALLBACK).

# Reusable test shape

The load-bearing assertion is cheap and must exist: build the real hashed artifact WITH and WITHOUT the quarantined facts on disk and assert the hash is byte-identical, plus a volume variant (N facts vs 0 facts → same hash). If that test can't be made to pass, the quarantine is leaking — stop and redesign, don't ship. Mirrors the broader OCH rule: [[determinism-is-the-only-uncontested-moat]] — protect the hash above all new features.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: New workspace package / export surfaces phantom "no exported member" until clean rebuild
track: bug
category: build-errors
severity: medium
tags: [pnpm, monorepo, tsc, tsbuildinfo, dist, workspace-link, mise-check, diagnostics, erpaval]
modules: [packages/core-types, packages/lsp-tier, packages/pack, packages/scip-ingest]
discovered: session-893add (2026-06-19)
---

# Symptom

After an Act agent adds a NEW export to a workspace package (e.g. `SCIP_UNOFFICIAL_PROVENANCE_PREFIXES` in `@opencodehub/core-types`) or a whole NEW workspace package (`@opencodehub/lsp-tier`), the editor / a fresh `tsc` reports against the CONSUMERS:

```
'"@opencodehub/core-types"' has no exported member named 'SCIP_UNOFFICIAL_PROVENANCE_PREFIXES'
Cannot find module '@opencodehub/lsp-tier' or its corresponding type declarations. [2307]
```

…even though the symbol IS defined and IS barrel-exported (verified with grep), and the agent reports `mise run check` exited 0.

# Root cause

Consumers in the monorepo typecheck against each package's **compiled `dist/` + `*.tsbuildinfo`**, not its `src/`. Two stale-state cases:

1. **New export:** core-types' `dist/` predates the new export. `mise run check` runs `build` BEFORE `test`, so the agent's run was genuinely green at its moment — but any diagnostic taken against the pre-build `dist` (editor LSP, a bare `tsc --noEmit` before the build step) fires a phantom "no exported member."
2. **New package:** a brand-new `@opencodehub/<name>` is not yet linked into the workspace (`pnpm install` not re-run) and/or not yet built, so `[2307] Cannot find module` until `pnpm install` symlinks it and a build emits its `dist`.

Both are stale-state artifacts, NOT real defects.

# Fix / verification protocol

Before trusting OR disbelieving a green/red typecheck after a cross-package export or new-package change:

```bash
find packages -name "*.tsbuildinfo" -delete # drop stale incremental state
pnpm install --frozen-lockfile # relink workspace (new package → "20 projects")
mise run check # build-then-test from clean; THIS is authoritative
```

- The `pnpm install` "Scope: all N workspace projects" count is a quick confirm a new package linked (it ticks up by one).
- `grep` the definition + barrel re-export to confirm the symbol genuinely exists; if it does and the error persists, it's stale `dist`, not a missing export.

# Why it matters for the orchestrator

In an ERPAVal session this fires as `<new-diagnostics>` streamed from a concurrent/just-finished Act agent. Do NOT commit on the agent's "exit 0" word and do NOT panic at the red diagnostic — run the clean protocol above and use ITS exit code as the gate. Hit twice in one session (T-A-S core-types export, T-A-L new lsp-tier package); both were stale state, both cleared on clean rebuild. Related but distinct: [[tsconfig-project-references-stale-on-package-removal]] (that one is package REMOVAL; this is ADDITION).
Loading
Loading