Skip to content

OCH v1.0 — M1 stabilize + M2 repo split / policy / wiki-split#53

Merged
theagenticguy merged 28 commits into
mainfrom
feat/v1-m1-m2
May 4, 2026
Merged

OCH v1.0 — M1 stabilize + M2 repo split / policy / wiki-split#53
theagenticguy merged 28 commits into
mainfrom
feat/v1-m1-m2

Conversation

@theagenticguy
Copy link
Copy Markdown
Owner

OCH v1.0 — M1 + M2

Closes: roadmap M1 + M2.
Branch: feat/v1-m1-m2main.
Pair repo: https://github.com/theagenticguy/opencodehub-testbed (new, initial commit cc4ea22)

M1 — Stabilize (14 commits)

  • T-M1-1 Dirty-tree guard on analyze fast-path — d3fa11b, b5e7068, fcdd9c9
  • T-M1-2 loadPreviousGraph full nodes+edges snapshot — 7b100fd, cca3c34, 7ebe4eb
  • T-M1-3 Embedder content-hash skip — 3cfb0cf, cca3c34, 8576f53
  • T-M1-4 SARIF symbol-level linkage — 5713b20, 96a4415, 927bde7
  • T-M1-5 Delete 5 canned MCP prompts (BREAKING) — 73d1375, b95cc90, a6a210f

M2 — Repo split + policy + wiki-split (14 commits)

  • T-M2-1 opencodehub-testbed repo + fixtures/evals/gyms extracted — 53d9b88, f6f5f68, 908afd3
  • T-M2-2 Delete codehub eval-server (BREAKING) — dde00ba, 5ac7473
  • T-M2-3 Delete packages/docs Starlight site (moves to separate repo) — 193f23e, 49673af
  • T-M2-4 @opencodehub/policy v1 (loader + evaluator + CLI wiring) — 7aba821, 02c9e61, 1e89b4e, 9bf34a7
  • T-M2-5 @opencodehub/wiki split from analysis — 289b122, 09e076c, f1de0cf

Metrics

  • LOC delta: +3,594 / −28,183 (net −24,589)
  • File count: 970 → 800 (−170; below the packet's <600 aspirational target — packages/ingestion at 249 files dominates and is request-time core)
  • Packages: 16 → 14 (−eval, −gym, −docs; +policy, +wiki)
  • Tests: cli 216, ingestion 579, mcp 137, analysis 114, scanners 80, embedder 70, core-types 65, storage 56, sarif 55, policy 29 (new), search 23, wiki 15 (new), scip-ingest 10 = 1,449 pass / 0 fail
  • mise run check: ✅ exit 0 at HEAD
  • graphHash byte-identity: preserved across M1+M2
  • Opus validate gate (M1): PASS-WITH-CONCERNS (3 non-blocking followups documented)

Breaking changes

  • MCP ListPrompts now returns empty (5 canned prompts removed; reimplemented as Claude Code skills in M3+)
  • CLI codehub eval-server removed (move to the testbed repo's nightly workflow)
  • packages/docs removed from monorepo (moved to separate repo; docs/adr/ at root stays)
  • packages/eval + packages/gym + bench/ moved to opencodehub-testbed
  • @opencodehub/analysis wiki re-exports marked @deprecated — import from @opencodehub/wiki going forward

Architecture changes

  • Wiki/analysis cycle break (T-M2-5): WikiOptions.loadTrends is now a caller-injected callback (CLI wires computeRiskTrends + loadSnapshots). Preserves byte-identical wiki output. Breaks composite-project cycle.
  • Policy v1 (T-M2-4): 3 rule types (license_allowlist, blast_radius_max, ownership_required). codehub verdict folds policy decision into output + exit code. v1 only blast_radius_max is actively enforced (license + changed-paths inputs are follow-ups).
  • SARIF symbol-level linkage (T-M1-4): findings now produce FOUND_IN edges keyed on enclosing-symbol id, not file id.

Followups (non-blocking, filed separately)

  1. C1: stringArrayField empty-array round-trip inconsistency (storage)
  2. C2: step=0 reader/writer asymmetry in graph edge handling
  3. C3: widen @internal TSDoc coverage on test-only exports in analyze.ts
  4. Replacement skills for 5 deleted MCP prompts (M3+)
  5. Bootstrap opencodehub-docs repo (docs moved out, repo not yet created)
  6. Policy v1 inputs: surface SBOM license audit + changed paths in verdict context so license_allowlist and ownership_required rules become load-bearing

The 5 MCP prompts (detect_impact, review_pr, explore_area,
audit_dependencies, generate_map) violated OCH v1.0's no-LLM-in-core
rail — they were canned LLM chains exposed over MCP that agents could
not compose with their own plans, parameterize dynamically, or chain
tool calls within. Delete them; the correct home for such playbooks
is plugins/opencodehub/skills/ (reimplementation is a downstream M3+
task).

Deletes packages/mcp/src/prompts/{audit-dependencies,detect-impact,
explore-area,generate-map,review-pr}.ts and their shared
prompts.test.ts.

BREAKING CHANGE: MCP clients that invoked any of these prompts by
name will now receive the standard "prompt not found" error.
Drops the 5 prompt registration calls, their imports, and the
prompts capability advert from packages/mcp/src/server.ts. The
canned LLM chains the prompts encoded belong in skills, not in core
(v1.0 no-LLM-in-core rail).

Also syncs the public docs:
- delete packages/docs/src/content/docs/mcp/prompts.md
- drop "prompts" capability + "5 prompts" section from
  mcp/overview.md; drop the prompts "See also" bullet from tools.md
- prune "/mcp/prompts" entries from inject-llm-nav.mjs
- SPECS.md: drop the "five built-in MCP prompts" clause and 6.7
- README.md: mcp row now reads "28 tools, resources"

The MCP SDK (1.29.0) accepts the server with no "prompts" capability
advertised — no empty placeholder needed.

BREAKING CHANGE: opencodehub's MCP surface no longer exposes the
detect_impact / review_pr / explore_area / audit_dependencies /
generate_map prompts.
Clone the tightest-enclosing-span lookup from scip-index.ts into the
CLI package so ingest-sarif can resolve SARIF results back to the
graph symbol that owns the line. Extracting a shared helper would
require moving between @opencodehub/cli and @opencodehub/ingestion, a
cross-package refactor that is out of scope for this task; the file
header flags the duplication for future consolidation.

Unit tests cover the basics: single and nested enclosure, tie-break
by span, inclusive boundaries, out-of-range lines, unknown files,
kind-filter dropping non-code rows, and short-circuit past the
target line. The allow set matches the packet conventions
(Function, Method, Constructor, Class, Interface, Struct, Enum,
Trait) and is a strict superset of SCIP_SYMBOL_KINDS — Constructor
is included because SARIF tooling routinely tags findings inside
constructor bodies.
… on dirty working tree

Probe `git status --porcelain` before comparing HEAD to the registry's
`lastCommit` so uncommitted changes invalidate the analyze fast-path.
Non-zero exits, spawn errors, and non-git dirs return `false` — keeping
the git-unavailable fallback aligned with `readGitHead`'s posture so
fresh indexes on non-git trees still short-circuit.

Note: per packet T-M1-1 the helper and wiring were to land in separate
commits, but Biome's `noUnusedVariables` rule blocks a helper-only
commit. Merged into one atomic change to satisfy the "every commit
passes lint" constraint; test coverage is split into two commits to
preserve the 3-commit success criterion.
Adds packages/mcp/src/server.test.ts — a server-wide wiring test
that builds the full McpServer via buildServer() and asserts its
internal _registeredPrompts map is empty, matching T-M1-5's EARS
requirement ("an MCP client calling ListPrompts receives an empty
result array").

This complements tool-handlers.test.ts which exercises individual
tool handlers against a fake store.
When a SARIF result carries (uri, startLine) but no scanner-provided
opencodehub.symbolId hint, ingest-sarif now resolves the tightest-
enclosing code symbol at that location and emits a second FOUND_IN
edge Finding -> Symbol alongside the existing Finding -> File edge.
Priority order: scanner-provided hint beats lookup, lookup beats
nothing; a file-only edge remains the fallback when neither resolves.

runIngestSarif opens the DuckDB store once and runs a scoped SELECT
(file_path IN <sarif URIs>, kind IN <code kinds>) to build the per-
file symbol index before buildFindingsGraph runs. buildFindingsGraph
now takes an optional nodesByFile index (empty map default preserves
the old file-only behavior for callers that omit it, such as the
existing unit tests).
Export `checkFastPath` and `isWorkingTreeDirty` so the CLI test suite
can exercise the new dirty-tree bypass directly, and cover the happy
path: a registry entry whose `lastCommit` matches HEAD hits the fast
path on a clean tree but falls through to a full analyze when the tree
has uncommitted edits. Test seeds a real temp git repo (via spawn, no
deps) and uses a scratch registry home so it cannot mutate user state.
Exercise the new nodesByFile path in buildFindingsGraph against a
hand-rolled per-file index so tests run without a live DuckDB:

- nested Class + Method enclosure → tightest (Method) wins
- line outside the Method but inside the Class → Class wins
- scanner-provided opencodehub.symbolId beats the enclosing lookup
- no enclosing symbol → only the File edge is emitted
- omitted nodesByFile argument → file-only edges (back-compat)

The storage-level SELECT is covered indirectly by the shape of
NodeRow and by existing DuckDB-adapter integration tests; this file
stays a pure unit suite so it can keep living under node --test.
Add two fallback-posture tests for `isWorkingTreeDirty` that document
the "cannot determine ⇒ not dirty" contract: a plain non-git directory
(git status exits non-zero) and a PATH that hides the git binary
(spawn raises ENOENT). Both must return false so non-git hosts and
locked-down CI environments still short-circuit via the registry.
loadPreviousGraph now queries every `nodes` and `relations` row from the
prior DuckDB index and maps them back into `GraphNode[]` / `CodeRelation[]`
via new `rowToGraphNode` + `rowToCodeRelation` helpers. Shipping these two
arrays flips `resolveIncrementalView`
(`packages/ingestion/src/pipeline/phases/incremental-helper.ts:95-102`)
from passive `active=false` to active carry-forward, so the four
incremental consumer phases (crossFile / mro / communities / processes)
reproduce a byte-identical graph hash on a second analyze of the same
commit.

`noUnusedLocals` + `exactOptionalPropertyTypes` gate any split into two
commits — the helpers and their caller land together.
…shot

New `analyze-carry-forward.test.ts` seeds a synthetic DuckDB index +
`.codehub/scan-state.json` with Community / Process / Function / File
nodes plus IMPORTS / CALLS / MEMBER_OF / PROCESS_STEP edges, calls
`loadPreviousGraph`, and asserts:

  1. the returned `PreviousGraph` has both `nodes` and `edges` populated
     (the exact precondition `resolveIncrementalView`
     `packages/ingestion/src/pipeline/phases/incremental-helper.ts:95-102`
     checks before flipping `active=true`),
  2. Community + Process fields round-trip verbatim via `rowToGraphNode`
     so the `communities` / `processes` phases can re-add them unchanged,
  3. edge-type coverage spans every phase the carry-forward feeds
     (crossFile → CALLS, communities → MEMBER_OF, processes →
     PROCESS_STEP),
  4. a missing prior DB still returns `undefined`.

Kept in a companion file (`analyze-carry-forward.test.ts`) so it composes
with the existing `analyze.test.ts` without step-on conflicts during
parallel M1 work.
The `codehub eval-server` loopback HTTP daemon violates OCH v1.0's
no-web-UI rail. SWE-bench-style eval loops move to the
`opencodehub-testbed` nightly workflow. Remove the subcommand, its
source tree, and its tests.

Deletes:
- packages/cli/src/eval-server/ (http-server, formatters, dispatch, next-steps)
- packages/cli/src/commands/eval-server.ts + .test.ts
- The `program.command("eval-server")` registration in packages/cli/src/index.ts

BREAKING CHANGE: `codehub eval-server` now errors with Commander's
"unknown command". No migration shim.
Follow-up to the eval-server deletion. Strips the CLI reference
section, the SPECS §7.1/§7.9 entries, and stale doc-comments in
MCP/analysis that mentioned the (now deleted) eval-server HTTP
adapter as a consumer of pure tool handlers.

Comment-only edits in packages/mcp and packages/analysis — no
runtime behaviour change.
The Starlight docs site has been the source of repeated `mise run check`
failures (Astro cache churn, dist/node_modules noise) and doesn't belong
in the core monorepo — docs will live in a dedicated repo or be served
from `docs/adr/` via GH Pages.

Removes `packages/docs/` entirely, regenerates `pnpm-lock.yaml` without
the astro / starlight / rehype-mermaid / playwright dep trees. Keeps
`docs/adr/` at repo root untouched.

Follow-up: bootstrap github.com/theagenticguy/opencodehub-docs.

BREAKING CHANGE: The `@opencodehub/docs` workspace package no longer
exists; any external tooling that invoked it (e.g. `pnpm -F
@opencodehub/docs ...`) will fail.
Follow-up to the deletion of `packages/docs/` — removes every remaining
reference to the Starlight site from root-level config and CI:

- `biome.json`: drop three `packages/docs/...` excludes
- `lefthook.yml`: drop `--filter='!@opencodehub/docs'` pre-push guards
- `mise.toml`: delete `docs:dev`, `docs:build`, `docs:preview` tasks
- `.gitignore`: drop `packages/docs/.astro/` Astro cache entry
- `README.md`: drop Starlight badge, drop docs row from repo layout
  (now 14 packages), repoint the Documentation section to `docs/adr/`
  and note the standalone docs repo is in-flight
- `.github/workflows/pages.yml`: deleted — nothing to deploy; the
  follow-up docs repo will own GH Pages
- `.github/workflows/ci.yml`, `gym.yml`: drop the
  `--filter='!@opencodehub/docs'` guards + justifying comments (they
  became no-ops when the package was removed)

`pnpm install && pnpm -r build && pnpm -r test` all exit 0 on
HEAD. `pnpm run lint`, `pnpm run typecheck`, and
`scripts/check-banned-strings.sh` likewise pass.
The Python parity/regression harness (49 parametrized cases across 14
language fixture trees) is heavy CI-only material. Moved to
github.com/theagenticguy/opencodehub-testbed where it runs nightly
against @opencodehub/cli@latest instead of the local tree.

Core-side fallout cleaned up in this commit:
- mise.toml: drop install:eval, test:eval, bootstrap depends only on
  install. Repoint the Python venv from packages/eval/.venv to .venv
  at the repo root (kept only for ad-hoc uv run).
- .github/dependabot.yml: drop pip ecosystem entry for /packages/eval.
- scripts/acceptance.sh: gate 9 (Python eval) is now a skip with a
  pointer to the testbed; the 5 ts-fixture consumers (gates 6, 10,
  12, 14, 15) repoint to a minimal local snapshot at
  scripts/fixtures/ts/ (4 files, ~1.5 KB) copied out of the former
  eval/fixtures tree.

No non-test core src imported @opencodehub/eval; boundary was already
clean. pnpm install / build / typecheck / test pass green.
…bed)

The SCIP-indexer evaluation harness (freeze/replay manifests, P/R/F1
metrics, three-layer regression gates) plus its multi-language corpus
(TypeScript, Python, Go, Rust, monorepo) and baseline manifests all
moved to github.com/theagenticguy/opencodehub-testbed. They run nightly
against @opencodehub/cli@latest.

Core-side fallout cleaned up in this commit:
- .github/workflows/gym.yml: deleted — gym CI workflow no longer
  applicable with the package gone.
- .gitmodules: deleted — all four submodule entries
  (strands-agents/sdk-python, ts-pattern, cobra, thiserror) pointed
  into packages/gym/corpus/repos/**. Those submodules now live in the
  testbed and get re-added there.
- mise.toml: drop gym, gym:baseline, gym:replay, gym:refresh-expected
  tasks. Block retained as a comment pointing at the testbed.
- biome.json: drop the now-dead "!packages/**/corpus/repos" ignore
  glob; no corpus directories remain in core.
- pnpm-lock.yaml: auto-updated to remove the workspace edge for
  @opencodehub/gym.

No non-test core src imported @opencodehub/gym; the only remaining
references live in packages/docs/ (owned by T-M2-3, will be updated
there) and historical ADRs/specs (kept for history). pnpm install /
build / typecheck / test pass green.
bench/ held rust-spike-report.md — the P/R/F1 benchmark writeup that
motivated the rust-core deferral (ADR 0002). It's historical /
reference material, not a core artifact. Moved to the testbed repo
alongside the gym + eval material so the core repo stays focused on
shippable source.

In-tree tests' minimal fixtures (packages/sarif/fixtures/*.sarif.json,
packages/scip-ingest/tests/fixtures/calcpkg.scip) stay in core — they
are load-bearing for test self-containment and total 3 tiny files. The
packet explicitly sanctioned this: "tests get minimized in-tree
fixtures while richer ones move out". Archival copies are mirrored
into the testbed's fixtures/ tree for reference.
Introduce packages/policy/ as a workspace-level pnpm package that
will host the loader + evaluator for opencodehub.policy.yaml
(consumed by codehub verdict once spec 002 P1 lands).

- package.json: Apache-2.0, deps on zod@4.3.6 and yaml@2.8.3.
- tsconfig.json: composite, extends the repo-wide base.
- schemas/policy-v1.ts: Zod schema for v1 with a discriminated union
  over license_allowlist, blast_radius_max, ownership_required and
  a passthrough auto_approve.require block.
- load.ts and evaluate.ts: typed public signatures, throw on call.
  Real implementations land in commits 2 and 3.
- index.ts: barrel export.
- README.md: surface overview, rule table, design notes.
- tsconfig.json (root): add the new package to project references.
- commitlint.config.mjs: allow "policy" scope.
Read opencodehub.policy.yaml with node:fs/promises, parse via the
yaml package, and validate against PolicySchema. Mirrors the EARS
state machine in T-M2-4:

- Missing file -> resolve undefined (ENOENT only; other fs errors
  propagate unchanged).
- Empty or all-comment YAML body -> resolve undefined. The starter
  file at the repo root ships in this state.
- Malformed YAML -> throw PolicyValidationError wrapping the
  yaml parser error.
- Schema failure -> throw PolicyValidationError whose message
  includes a Zod path + message per issue so codehub verdict
  can surface it rather than silently pass.
- Well-formed file -> typed Policy with rules defaulted to [].

Tests (16 total) cover every branch plus the full 3-rule starter
example and direct Zod schema exercises in schemas/policy-v1.test.ts.
Pure evaluator: takes a Policy + a pre-computed PolicyContext and
returns a deterministic PolicyDecision with violations sorted by
ruleId (stable across CI runs).

Rule evaluators:
- license_allowlist: block + one violation per denied hit in
  ctx.licenseViolations.
- blast_radius_max: block when ctx.blastRadiusTier > rule.max_tier.
- ownership_required: match ctx.touchedPaths against the rule's
  glob patterns (* = single segment, ** = multi-segment). For each
  matched path, require an approval from require_approval_from or
  an owner attached via ctx.ownersByPath; emit a dedicated
  "no owners" violation when neither is known.

Status is pass when violations is empty, else block. The warn arm
of the union is reserved for future warn-severity rules (ADR TBD).

Tests (13) cover every rule type's pass + fail path, the glob
matcher, and multi-rule sort determinism. Total package tests: 29.
Fold @opencodehub/policy into runVerdict so opencodehub.policy.yaml
at the repo root is enforced as part of the 5-tier verdict.

- Add @opencodehub/policy as a workspace dep (+ tsconfig project ref).
- Load policy from <repoPath>/opencodehub.policy.yaml via loadPolicy.
  Missing file -> skip (unchanged behavior). Malformed file ->
  PolicyValidationError propagates so verdict exits non-zero rather
  than silently pass.
- Build a v1 PolicyContext from VerdictResponse: map VerdictTier ->
  numeric policy tier via POLICY_TIER_FOR_VERDICT (auto_merge=1 to
  block=5). licenseViolations and touchedPaths are empty until the
  SBOM license + changed-paths pipelines surface their data — noted
  inline.
- Extend output:
    - json -> parsed, merged with a `policy` key, re-stringified.
    - markdown -> append ### Policy section with violations.
    - summary -> append `Policy: <status>` + one line per violation.
- Exit code: max(tierExit, 3 when policy blocks). A policy-block on
  an auto_merge verdict exits 3 so CI surfaces the policy gate.
- Add VerdictCliOptions.loadPolicyFn and .approvals test hooks.
- New tests (7): tier map, no-file pass-through, no-rules pass,
  blast_radius_max block + exit 3, pr-comment markdown section,
  malformed throws, ownership_required pass with approval.

Fix: captureStdout helper now passes non-string (binary) writes
through to the real stdout instead of stringifying them. Node's
test-runner TAP reporter writes v8-serialized Buffer frames
during await boundaries; previously, the extra loadPolicy await
let those frames land in the chunk buffer and corrupt
JSON.parse assertions in two pre-existing tests.

mise run check exits 0. Total package tests: policy 29, cli 196.
Split the 5 page-family renderers (architecture, api-surface,
dependency-map, ownership-map, risk-atlas) plus the generateWiki
entrypoint and the opt-in llm-overview module out of
@opencodehub/analysis into a new @opencodehub/wiki workspace package.
All 10 files moved via git mv to preserve blame.

@opencodehub/analysis retains a compat shim (re-exports generateWiki +
types from @opencodehub/wiki) so existing consumers keep working
without changes in this commit.

To break the wiki/analysis composite reference cycle, risk-atlas uses
dependency inversion: WikiOptions.loadTrends is an optional callback
the caller injects. A structural RiskTrendsLike type keeps the
renderer free of analysis internals. All public names are preserved.

Commit 2 adds @deprecated markers and trims unused analysis deps.
Commit 3 switches the CLI to import from @opencodehub/wiki directly.

Also adds "wiki" to commitlint scope-enum per the config's own note
about extending it when new workspace packages land.
Mark the wiki compat shim as @deprecated so consumers get a migration
signal pointing to @opencodehub/wiki. Re-exports continue to work for
one release.

Drop now-unused dependencies from @opencodehub/analysis:
- @aws-sdk/client-bedrock-runtime (only used by wiki/llm-overview)
- @opencodehub/summarizer (ditto)

Drop the summarizer tsconfig project reference for the same reason.
Switch the codehub wiki command to import generateWiki and
WikiLlmOptions from @opencodehub/wiki directly, skipping the
@opencodehub/analysis compat shim.

The CLI now injects a loadTrends callback that calls into
@opencodehub/analysis (loadSnapshots + computeRiskTrends). This
keeps @opencodehub/wiki free of any analysis dependency while
preserving byte-identical wiki output — the callback executes the
same code path as before.

Adds @opencodehub/wiki as a workspace dep and project reference.
@theagenticguy theagenticguy enabled auto-merge (squash) May 4, 2026 17:15
@theagenticguy theagenticguy disabled auto-merge May 4, 2026 17:15
@theagenticguy theagenticguy merged commit 4431b53 into main May 4, 2026
14 checks passed
@theagenticguy theagenticguy deleted the feat/v1-m1-m2 branch May 4, 2026 17:16
theagenticguy added a commit that referenced this pull request May 10, 2026
…section (#87)

## Summary

The OpenCodeHub Starlight docs site was deleted in PR #53 (May 4, commit
`4431b53`) under T-M2-3 with the explicit promise to spin it up as
`theagenticguy/opencodehub-docs`. That separate repo was never created.
The site at https://theagenticguy.github.io/opencodehub/ has been
serving the May 1 snapshot ever since — 28-tool / DuckDB-default / Node
20 / 14-language prose, missing every milestone since (M3-M7, Track A-D,
parse-runtime flip, 20-scanner inventory, supply-chain hardening).

This PR restores `packages/docs/` + `.github/workflows/pages.yml` from
`4431b53^`, refreshes every page against v1 reality, adds a deep
agent-friendly `agents/` section, ships a machine-readable tool catalog,
hardens the workflow, and lifts `LadybugDB` out of the banned-strings
policy now that it's a first-class product name.

Three deep specialists ran in parallel after the bulk-restore, with one
polish pass at the end.

## What's in here

### Restoration (`f801f1a`)
56 files restored from history. Build clean out of the box: 47 pages,
links valid, Pagefind index, llm-nav banners.

### Content refresh (8 commits, `00a0fce` → `c0376d8`)
- **Start here** — install (Node 22 or 24, mise, `codehub init`),
quick-start (first MCP call), what-is-opencodehub, codehub-init,
first-query — all v1.
- **MCP** — `mcp/overview.md` reframes 29 tools across five families
(exploration, group/federation, scan/findings/verdict, HTTP/routing,
meta). `mcp/tools.md` rewritten as full per-tool catalog with
when-to-use / when-not-to-use / signature / example. `mcp/resources.md`
+ `mcp/prompts.md` updated.
- **Reference** — `cli.md` verified against `packages/cli/src/index.ts`
shape; `configuration.md` env-var inventory + `AMBIGUOUS_REPO` envelope
+ `EMBEDDER_MISMATCH` from ADR 0014; `languages.md` 15-language table;
`error-codes.md` current set.
- **Architecture** — overview, monorepo-map (17 packages, dropped
eval/gym, added cobol-proleap/frameworks/pack/policy/wiki), embeddings
(3-backend precedence), parsing-and-resolution (WASM-default + native
opt-in), determinism (graphHash invariant), scanners-and-sarif
(20-scanner inventory), scip-reconciliation, supply-chain, adrs
(0001-0014 index).
- **New architecture pages** — `storage-backend.md` (LadybugDB + DuckDB
segregation, IGraphStore/ITemporalStore, community-adapter escape
hatch); `cross-repo-federation.md` (repo-as-typed-node, AMBIGUOUS_REPO,
group_* tools); `lessons.md` (pointer to `.erpaval/solutions/`).
- **New guides** — `migrating-from-duckdb.md` (three migration paths).
- **Index hero** — splash with three CTAs (Install / Use / Develop)
using Starlight `<Card>` / `<CardGrid>` — no marketing tiles.
- **Sidebar IA** — Start here · Agents · MCP · Reference · Guides ·
Architecture · Skills · Contributing.
- **astro.config llms-txt** — `description` + `details` rewritten with
current 29-tool / 15-language / LadybugDB-default reality (per the
durable lesson `llms-txt-as-ground-truth.md`).

### Tool catalog as data (`b112b67`)
`packages/docs/public/tool-catalog.json` — machine-readable canonical
catalog of all 29 tools. Schema: `{ tools: [{ name, family, description,
when_to_use, when_not_to_use, signature_sketch, example }] }`. Agents
can
`fetch('https://theagenticguy.github.io/opencodehub/tool-catalog.json')`.

### Agents section (4 commits, `4e55203` → `3547b74`)
A new `packages/docs/src/content/docs/agents/` section, 14 pages,
dedicated to AI-coding-agent discovery + usage:
- `agents/index.md` — section landing with 90-second setup + 5-editor
card grid.
- `agents/why-mcp.md` — what an agent can't see without the graph; three
failure modes; four MCP tool families.
- `agents/install.md` — generic install for any MCP-speaking agent:
prereqs, `mise run cli:link`, `codehub init` (writes `.mcp.json` +
plugin link), `codehub analyze`, `codehub doctor`, per-editor handoff.
- `agents/editors/claude-code.md` — deepest editor page: `.mcp.json`
shape, 5 slash commands, `code-analyst` subagent, all 11 skills tabled,
`hooks.json`.
- `agents/editors/cursor.md` — `.cursor/mcp.json` (project + global),
absolute-path fallback, verification.
- `agents/editors/codex.md` — `~/.codex/config.toml` + CLI helper,
stdio-only caveat.
- `agents/editors/windsurf.md` — `~/.codeium/windsurf/mcp_config.json`,
restart caveat.
- `agents/editors/opencode.md` — `opencode.json` with the differing key
shape (`mcp` vs `mcpServers`, `command: [...]`, `environment` vs `env`).
- `agents/tool-decision-matrix.md` — 21-row single-repo intent → tool
table with anti-pattern column, plus 5-row group-mode table and a "When
to chain" section.
- `agents/idiomatic-prompts.md` — 5 paste-ready prompts (rename audit /
auth-flow surfacing / HTTP contract reconstruction /
findings-vs-baseline / onboarding) with target editor + expected tool
calls + expected output.
- `agents/discovery-and-resources.md` — site URL, `/llms.txt`,
`/llms-full.txt`, `/llms-small.txt`, `/tool-catalog.json`, `AGENTS.md`,
`CLAUDE.md`, registries.
- `agents/registries.md` — Official MCP Registry (`server.json` shape),
Smithery (`smithery.yaml` shape), Glama, awesome-mcp-servers, aggregator
directories.
- `agents/llms-txt-cheatsheet.md` — picking guidance for the three core
bundles + custom sets.

### Banned-strings policy (`d8dddb2`)
Removed `ladybug` and `kuzu` from `BANNED_LITERALS` in
`scripts/check-banned-strings.sh`. LadybugDB is the default graph
backend (M7) and a first-class product name in docs. The original ban
dated from when the project was still deciding which graph engine to
vendor; that decision shipped. `kuzu` is retained as historical lineage
in cross-link prose ("the open-source successor to the pre-1.0 Kuzu
codebase") which already lives in ADR 0011.

### Pages workflow hardening (`c54231d`)
- `actions/checkout@v6` → `@de0fac2e...` (v6.0.2)
- `jdx/mise-action@v4` → `@c37c9329...` (v2.4.4)
- `actions/upload-pages-artifact@v5` → `@fc324d35...`
- `actions/deploy-pages@v5` → `@cd2ce8fc...`

Top-level `permissions: contents: read`; write scopes (`pages: write` +
`id-token: write`) granted only on the `deploy` job. Resolves the same
Token-Permissions HIGH pattern fixed in PR #78 for the other 4
workflows.

### LadybugDB polish (`3c7166b`)
38 prose substitutions across 13 files: replace awkward "the
graph-database backend" workarounds with plain "LadybugDB" now that the
literal is allowed. `@ladybugdb/core` (npm package) and `graph.lbug`
(file extension) preserved.

## Validation

- `mise run check` exit 0 — 1,339 tests across 8 packages (lint +
typecheck + test + banned-strings + verdict)
- `pnpm -F @opencodehub/docs build` — **64 pages built, all internal
links valid**, Pagefind index ok, llm-nav banners patch all 63 .md files
- `actionlint .github/workflows/*.yml` — clean
- `bash scripts/check-banned-strings.sh` — PASS
- `rg
'AC-[A-Z]-[0-9]|T-M[0-9]+-[0-9]+|W-[A-Z]-[0-9]+|S-[A-Z]-[0-9]+|E-[A-Z]-[0-9]+|CL-[A-Z]+|architecture-revised\.md'
packages/docs/src/` — zero hits
- Marketing-words sweep (`effortless`, `leverage`, `synergy`,
`world-class`, `blazing-fast`, `cutting-edge`) — zero hits in docs prose

## Test plan

- [ ] CI green on `docs/site-restore-v1`
- [ ] After merge, the Pages workflow at `.github/workflows/pages.yml`
triggers on first push to `main` (paths-filter on `packages/docs/**`)
- [ ] Deployed site at https://theagenticguy.github.io/opencodehub/
replaces the May 1 snapshot
- [ ] Manual verification: visit /agents/, /mcp/tools/,
/tool-catalog.json
- [ ] Manual verification: `/llms.txt`, `/llms-full.txt`,
`/llms-small.txt` all resolve and contain "29 tools" / "LadybugDB" /
"WASM" facts

## Out of scope

- Submission to `skills.sh`, the official MCP Registry, Smithery,
awesome-mcp-servers — research file at
`.erpaval/sessions/session-05809d/research-skills-sh.md` and
`.erpaval/sessions/session-05809d/research-agent-docs.md` capture the
exact shape; PR-able as separate follow-ups.
- Importing `.erpaval/solutions/**.md` as a Starlight content collection
— investigated, deemed not worth shipping (lessons audience is the agent
at edit-time, not docs readers; some lesson titles include literals the
docs build's other guardrails reject). The `architecture/lessons.md`
stub points readers at the directory.
theagenticguy added a commit that referenced this pull request May 10, 2026
## Summary

Compound phase from session-05809d (PR #87). Three new durable lessons
from the Starlight docs site revival.

| File | Category | Surfaced by |
|---|---|---|
| `post-deletion-promise-debt-anti-pattern.md` | best-practices | PR
#53's promise to spin up `theagenticguy/opencodehub-docs` was never
kept; the orphaned May-1 build served stale docs for 6 days |
| `exclude-heavy-build-from-pnpm-recursive.md` | architecture-patterns |
Restoring `@opencodehub/docs` broke `ci.yml` typecheck, `och-self-scan`,
and `release.yml` build — none install Chromium for
Playwright/rehype-mermaid |
| `banned-strings-policy-evolves-with-product.md` | conventions |
LadybugDB was banned during graph-engine evaluation; after M3+M7 made it
the default, the bare product name became critical prose surface |

## Test plan

- [ ] CI green
- [ ] Future ERPAVal sessions surface these three on `INDEX.md`
theagenticguy added a commit that referenced this pull request May 10, 2026
# OCH v1.0 — M1 + M2

Closes: roadmap M1 + M2.
Branch: `feat/v1-m1-m2` → `main`.
Pair repo: https://github.com/theagenticguy/opencodehub-testbed (new,
initial commit `cc4ea22`)

## M1 — Stabilize (14 commits)

- **T-M1-1** Dirty-tree guard on analyze fast-path — `d3fa11b`,
`b5e7068`, `fcdd9c9`
- **T-M1-2** `loadPreviousGraph` full nodes+edges snapshot — `7b100fd`,
`cca3c34`, `7ebe4eb`
- **T-M1-3** Embedder content-hash skip — `3cfb0cf`, `cca3c34`,
`8576f53`
- **T-M1-4** SARIF symbol-level linkage — `5713b20`, `96a4415`,
`927bde7`
- **T-M1-5** Delete 5 canned MCP prompts (BREAKING) — `73d1375`,
`b95cc90`, `a6a210f`

## M2 — Repo split + policy + wiki-split (14 commits)

- **T-M2-1** `opencodehub-testbed` repo + fixtures/evals/gyms extracted
— `53d9b88`, `f6f5f68`, `908afd3`
- **T-M2-2** Delete `codehub eval-server` (BREAKING) — `dde00ba`,
`5ac7473`
- **T-M2-3** Delete `packages/docs` Starlight site (moves to separate
repo) — `193f23e`, `49673af`
- **T-M2-4** `@opencodehub/policy` v1 (loader + evaluator + CLI wiring)
— `7aba821`, `02c9e61`, `1e89b4e`, `9bf34a7`
- **T-M2-5** `@opencodehub/wiki` split from analysis — `289b122`,
`09e076c`, `f1de0cf`

## Metrics

- **LOC delta**: +3,594 / −28,183 (net −24,589)
- **File count**: 970 → 800 (−170; below the packet's <600 aspirational
target — `packages/ingestion` at 249 files dominates and is request-time
core)
- **Packages**: 16 → 14 (−eval, −gym, −docs; +policy, +wiki)
- **Tests**: cli 216, ingestion 579, mcp 137, analysis 114, scanners 80,
embedder 70, core-types 65, storage 56, sarif 55, policy 29 (new),
search 23, wiki 15 (new), scip-ingest 10 = **1,449 pass / 0 fail**
- **`mise run check`**: ✅ exit 0 at HEAD
- **graphHash byte-identity**: preserved across M1+M2
- **Opus validate gate (M1)**: PASS-WITH-CONCERNS (3 non-blocking
followups documented)

## Breaking changes

- MCP `ListPrompts` now returns empty (5 canned prompts removed;
reimplemented as Claude Code skills in M3+)
- CLI `codehub eval-server` removed (move to the testbed repo's nightly
workflow)
- `packages/docs` removed from monorepo (moved to separate repo;
`docs/adr/` at root stays)
- `packages/eval` + `packages/gym` + `bench/` moved to
`opencodehub-testbed`
- `@opencodehub/analysis` wiki re-exports marked `@deprecated` — import
from `@opencodehub/wiki` going forward

## Architecture changes

- **Wiki/analysis cycle break** (T-M2-5): `WikiOptions.loadTrends` is
now a caller-injected callback (CLI wires `computeRiskTrends +
loadSnapshots`). Preserves byte-identical wiki output. Breaks
composite-project cycle.
- **Policy v1** (T-M2-4): 3 rule types (`license_allowlist`,
`blast_radius_max`, `ownership_required`). `codehub verdict` folds
policy decision into output + exit code. v1 only `blast_radius_max` is
actively enforced (license + changed-paths inputs are follow-ups).
- **SARIF symbol-level linkage** (T-M1-4): findings now produce
`FOUND_IN` edges keyed on enclosing-symbol id, not file id.

## Followups (non-blocking, filed separately)

1. **C1**: `stringArrayField` empty-array round-trip inconsistency
(storage)
2. **C2**: `step=0` reader/writer asymmetry in graph edge handling
3. **C3**: widen `@internal` TSDoc coverage on test-only exports in
`analyze.ts`
4. **Replacement skills** for 5 deleted MCP prompts (M3+)
5. **Bootstrap `opencodehub-docs` repo** (docs moved out, repo not yet
created)
6. **Policy v1 inputs**: surface SBOM license audit + changed paths in
`verdict` context so `license_allowlist` and `ownership_required` rules
become load-bearing
theagenticguy added a commit that referenced this pull request May 10, 2026
…section (#87)

## Summary

The OpenCodeHub Starlight docs site was deleted in PR #53 (May 4, commit
`ecc86a3`) under T-M2-3 with the explicit promise to spin it up as
`theagenticguy/opencodehub-docs`. That separate repo was never created.
The site at https://theagenticguy.github.io/opencodehub/ has been
serving the May 1 snapshot ever since — 28-tool / DuckDB-default / Node
20 / 14-language prose, missing every milestone since (M3-M7, Track A-D,
parse-runtime flip, 20-scanner inventory, supply-chain hardening).

This PR restores `packages/docs/` + `.github/workflows/pages.yml` from
`ecc86a3^`, refreshes every page against v1 reality, adds a deep
agent-friendly `agents/` section, ships a machine-readable tool catalog,
hardens the workflow, and lifts `LadybugDB` out of the banned-strings
policy now that it's a first-class product name.

Three deep specialists ran in parallel after the bulk-restore, with one
polish pass at the end.

## What's in here

### Restoration (`d393ecf`)
56 files restored from history. Build clean out of the box: 47 pages,
links valid, Pagefind index, llm-nav banners.

### Content refresh (8 commits, `3148769` → `1eb333d`)
- **Start here** — install (Node 22 or 24, mise, `codehub init`),
quick-start (first MCP call), what-is-opencodehub, codehub-init,
first-query — all v1.
- **MCP** — `mcp/overview.md` reframes 29 tools across five families
(exploration, group/federation, scan/findings/verdict, HTTP/routing,
meta). `mcp/tools.md` rewritten as full per-tool catalog with
when-to-use / when-not-to-use / signature / example. `mcp/resources.md`
+ `mcp/prompts.md` updated.
- **Reference** — `cli.md` verified against `packages/cli/src/index.ts`
shape; `configuration.md` env-var inventory + `AMBIGUOUS_REPO` envelope
+ `EMBEDDER_MISMATCH` from ADR 0014; `languages.md` 15-language table;
`error-codes.md` current set.
- **Architecture** — overview, monorepo-map (17 packages, dropped
eval/gym, added cobol-proleap/frameworks/pack/policy/wiki), embeddings
(3-backend precedence), parsing-and-resolution (WASM-default + native
opt-in), determinism (graphHash invariant), scanners-and-sarif
(20-scanner inventory), scip-reconciliation, supply-chain, adrs
(0001-0014 index).
- **New architecture pages** — `storage-backend.md` (LadybugDB + DuckDB
segregation, IGraphStore/ITemporalStore, community-adapter escape
hatch); `cross-repo-federation.md` (repo-as-typed-node, AMBIGUOUS_REPO,
group_* tools); `lessons.md` (pointer to `.erpaval/solutions/`).
- **New guides** — `migrating-from-duckdb.md` (three migration paths).
- **Index hero** — splash with three CTAs (Install / Use / Develop)
using Starlight `<Card>` / `<CardGrid>` — no marketing tiles.
- **Sidebar IA** — Start here · Agents · MCP · Reference · Guides ·
Architecture · Skills · Contributing.
- **astro.config llms-txt** — `description` + `details` rewritten with
current 29-tool / 15-language / LadybugDB-default reality (per the
durable lesson `llms-txt-as-ground-truth.md`).

### Tool catalog as data (`b3aed17`)
`packages/docs/public/tool-catalog.json` — machine-readable canonical
catalog of all 29 tools. Schema: `{ tools: [{ name, family, description,
when_to_use, when_not_to_use, signature_sketch, example }] }`. Agents
can
`fetch('https://theagenticguy.github.io/opencodehub/tool-catalog.json')`.

### Agents section (4 commits, `c771f40` → `473cb82`)
A new `packages/docs/src/content/docs/agents/` section, 14 pages,
dedicated to AI-coding-agent discovery + usage:
- `agents/index.md` — section landing with 90-second setup + 5-editor
card grid.
- `agents/why-mcp.md` — what an agent can't see without the graph; three
failure modes; four MCP tool families.
- `agents/install.md` — generic install for any MCP-speaking agent:
prereqs, `mise run cli:link`, `codehub init` (writes `.mcp.json` +
plugin link), `codehub analyze`, `codehub doctor`, per-editor handoff.
- `agents/editors/claude-code.md` — deepest editor page: `.mcp.json`
shape, 5 slash commands, `code-analyst` subagent, all 11 skills tabled,
`hooks.json`.
- `agents/editors/cursor.md` — `.cursor/mcp.json` (project + global),
absolute-path fallback, verification.
- `agents/editors/codex.md` — `~/.codex/config.toml` + CLI helper,
stdio-only caveat.
- `agents/editors/windsurf.md` — `~/.codeium/windsurf/mcp_config.json`,
restart caveat.
- `agents/editors/opencode.md` — `opencode.json` with the differing key
shape (`mcp` vs `mcpServers`, `command: [...]`, `environment` vs `env`).
- `agents/tool-decision-matrix.md` — 21-row single-repo intent → tool
table with anti-pattern column, plus 5-row group-mode table and a "When
to chain" section.
- `agents/idiomatic-prompts.md` — 5 paste-ready prompts (rename audit /
auth-flow surfacing / HTTP contract reconstruction /
findings-vs-baseline / onboarding) with target editor + expected tool
calls + expected output.
- `agents/discovery-and-resources.md` — site URL, `/llms.txt`,
`/llms-full.txt`, `/llms-small.txt`, `/tool-catalog.json`, `AGENTS.md`,
`CLAUDE.md`, registries.
- `agents/registries.md` — Official MCP Registry (`server.json` shape),
Smithery (`smithery.yaml` shape), Glama, awesome-mcp-servers, aggregator
directories.
- `agents/llms-txt-cheatsheet.md` — picking guidance for the three core
bundles + custom sets.

### Banned-strings policy (`a85a8f4`)
Removed `ladybug` and `kuzu` from `BANNED_LITERALS` in
`scripts/check-banned-strings.sh`. LadybugDB is the default graph
backend (M7) and a first-class product name in docs. The original ban
dated from when the project was still deciding which graph engine to
vendor; that decision shipped. `kuzu` is retained as historical lineage
in cross-link prose ("the open-source successor to the pre-1.0 Kuzu
codebase") which already lives in ADR 0011.

### Pages workflow hardening (`808d97f`)
- `actions/checkout@v6` → `@de0fac2e...` (v6.0.2)
- `jdx/mise-action@v4` → `@c37c9329...` (v2.4.4)
- `actions/upload-pages-artifact@v5` → `@fc324d35...`
- `actions/deploy-pages@v5` → `@cd2ce8fc...`

Top-level `permissions: contents: read`; write scopes (`pages: write` +
`id-token: write`) granted only on the `deploy` job. Resolves the same
Token-Permissions HIGH pattern fixed in PR #78 for the other 4
workflows.

### LadybugDB polish (`3d78ab8`)
38 prose substitutions across 13 files: replace awkward "the
graph-database backend" workarounds with plain "LadybugDB" now that the
literal is allowed. `@ladybugdb/core` (npm package) and `graph.lbug`
(file extension) preserved.

## Validation

- `mise run check` exit 0 — 1,339 tests across 8 packages (lint +
typecheck + test + banned-strings + verdict)
- `pnpm -F @opencodehub/docs build` — **64 pages built, all internal
links valid**, Pagefind index ok, llm-nav banners patch all 63 .md files
- `actionlint .github/workflows/*.yml` — clean
- `bash scripts/check-banned-strings.sh` — PASS
- `rg
'AC-[A-Z]-[0-9]|T-M[0-9]+-[0-9]+|W-[A-Z]-[0-9]+|S-[A-Z]-[0-9]+|E-[A-Z]-[0-9]+|CL-[A-Z]+|architecture-revised\.md'
packages/docs/src/` — zero hits
- Marketing-words sweep (`effortless`, `leverage`, `synergy`,
`world-class`, `blazing-fast`, `cutting-edge`) — zero hits in docs prose

## Test plan

- [ ] CI green on `docs/site-restore-v1`
- [ ] After merge, the Pages workflow at `.github/workflows/pages.yml`
triggers on first push to `main` (paths-filter on `packages/docs/**`)
- [ ] Deployed site at https://theagenticguy.github.io/opencodehub/
replaces the May 1 snapshot
- [ ] Manual verification: visit /agents/, /mcp/tools/,
/tool-catalog.json
- [ ] Manual verification: `/llms.txt`, `/llms-full.txt`,
`/llms-small.txt` all resolve and contain "29 tools" / "LadybugDB" /
"WASM" facts

## Out of scope

- Submission to `skills.sh`, the official MCP Registry, Smithery,
awesome-mcp-servers — research file at
`.erpaval/sessions/session-05809d/research-skills-sh.md` and
`.erpaval/sessions/session-05809d/research-agent-docs.md` capture the
exact shape; PR-able as separate follow-ups.
- Importing `.erpaval/solutions/**.md` as a Starlight content collection
— investigated, deemed not worth shipping (lessons audience is the agent
at edit-time, not docs readers; some lesson titles include literals the
docs build's other guardrails reject). The `architecture/lessons.md`
stub points readers at the directory.
theagenticguy added a commit that referenced this pull request May 10, 2026
## Summary

Compound phase from session-05809d (PR #87). Three new durable lessons
from the Starlight docs site revival.

| File | Category | Surfaced by |
|---|---|---|
| `post-deletion-promise-debt-anti-pattern.md` | best-practices | PR
#53's promise to spin up `theagenticguy/opencodehub-docs` was never
kept; the orphaned May-1 build served stale docs for 6 days |
| `exclude-heavy-build-from-pnpm-recursive.md` | architecture-patterns |
Restoring `@opencodehub/docs` broke `ci.yml` typecheck, `och-self-scan`,
and `release.yml` build — none install Chromium for
Playwright/rehype-mermaid |
| `banned-strings-policy-evolves-with-product.md` | conventions |
LadybugDB was banned during graph-engine evaluation; after M3+M7 made it
the default, the bare product name became critical prose surface |

## Test plan

- [ ] CI green
- [ ] Future ERPAVal sessions surface these three on `INDEX.md`
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