Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 8 additions & 8 deletions context/map/artifact-1-territory.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- GENERATED by tools/repo-map/scan.mjs — do not hand-edit. Run `npm run repo-map`. -->

> Scan of `cb4b636` (2026-07-28) · window: last 12 months · engine: tools/repo-map
> Scan of `863bf16` (2026-07-28) · window: last 12 months · engine: tools/repo-map

**Where the work actually happens.** Git-history activity over the last 12 months, noise filtered (lockfiles, generated files, assets). Activity is a signal of *risk of accidental regression*, not of quality.

Expand All @@ -12,7 +12,7 @@
| --- | --- |
| `src/lib` | 75 |
| `context/changes` | 53 |
| `context/map` | 37 |
| `context/map` | 42 |
| `tests/e2e` | 32 |
| `src/commands` | 30 |
| `package.json` | 28 |
Expand All @@ -37,12 +37,12 @@
| `src/lib/writer.ts` | 12 |
| `README.md` | 9 |
| `tests/writer.test.ts` | 9 |
| `context/map/artifact-1-territory.md` | 8 |
| `context/map/artifact-2-structure.md` | 8 |
| `context/map/artifact-3-contributors.md` | 8 |
| `context/map/graph/coupling.json` | 8 |
| `context/map/repo-map.md` | 8 |
| `src/lib/config.ts` | 8 |
| `context/map/artifact-1-territory.md` | 7 |
| `context/map/artifact-2-structure.md` | 7 |
| `context/map/artifact-3-contributors.md` | 7 |
| `context/map/graph/coupling.json` | 7 |
| `context/map/repo-map.md` | 7 |
| `src/lib/manifest.ts` | 7 |
| `src/lib/api-content.ts` | 7 |

Expand All @@ -52,7 +52,7 @@
| --- | --- | --- |
| `src/lib` | 34 | 1 |
| `context/changes` | 28 | 1 |
| `context/map` | 0 | 7 |
| `context/map` | 0 | 8 |
| `tests/e2e` | 11 | 0 |
| `src/commands` | 23 | 0 |

Expand Down
10 changes: 3 additions & 7 deletions context/map/artifact-2-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- GENERATED by tools/repo-map/scan.mjs — do not hand-edit. Run `npm run repo-map`. -->

> Scan of `cb4b636` (2026-07-28) · window: last 12 months · engine: tools/repo-map
> Scan of `863bf16` (2026-07-28) · window: last 12 months · engine: tools/repo-map

**How it is built.** Static import graph of `src` plus a file inventory of every module. Folders show where the code is; the graph shows what actually depends on what.

Expand All @@ -20,13 +20,9 @@ _None detected this run._

## Highest fan-out folders (efferent coupling Ce — depends on many)

| Folder | Ce (out) | Ca (in, lower bound) | Modules |
| --- | --- | --- | --- |
| `src/commands` | 38 | 5 | 5 |
| `src` | 24 | 0 | 25 |
| `src/lib` | 17 | 33 | 19 |
_Metrics unavailable this run (see limitations)._

## Limitations

- Afferent coupling (Ca) from dependency-cruiser is unreliable without a fully installed toolchain (external/aliased imports go unresolved). Treat Ca as a lower bound.
- dependency-cruiser not runnable — coupling metrics skipped this run.
- Static import graph only. Runtime wiring (dynamic import, template refs, feature flags, codegen) is invisible here and is an `unknown`, not "no dependency".
2 changes: 1 addition & 1 deletion context/map/artifact-3-contributors.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- GENERATED by tools/repo-map/scan.mjs — do not hand-edit. Run `npm run repo-map`. -->

> Scan of `cb4b636` (2026-07-28) · window: last 12 months · engine: tools/repo-map
> Scan of `863bf16` (2026-07-28) · window: last 12 months · engine: tools/repo-map

**Who to ask before you change something.** Bots and AI agents (Claude, Codex, Copilot, dependabot…) are filtered out — this is about humans who hold undocumented context. Answers "who has context on this area", not "who changed this line" (that is `git blame`).

Expand Down
13 changes: 5 additions & 8 deletions context/map/repo-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- GENERATED by tools/repo-map/scan.mjs — do not hand-edit. Run `npm run repo-map`. -->

> Scan of `cb4b636` (2026-07-28) · window: last 12 months · engine: tools/repo-map
> Scan of `863bf16` (2026-07-28) · window: last 12 months · engine: tools/repo-map
>
> Operational map of the territory, built from cheap deterministic signals (git history + import graph), synthesized for decisions — not an essay. A new developer should know in ~15 min where things live, what is dangerous, and where to start. Refresh with `npm run repo-map`.

Expand Down Expand Up @@ -30,7 +30,7 @@ Top active areas (full table in `artifact-1-territory.md`):
| --- | --- |
| `src/lib` | 75 |
| `context/changes` | 53 |
| `context/map` | 37 |
| `context/map` | 42 |
| `tests/e2e` | 32 |
| `src/commands` | 30 |
| `package.json` | 28 |
Expand All @@ -54,10 +54,7 @@ Structural coupling and cycles live in `artifact-2-structure.md` and `graph/`.

## 4. Risk zones — where to be careful

| Zone | What | Why it matters (evidence) |
| --- | --- | --- |
| `src/commands` | Fan-out Ce=38 across 5 modules | Depends on many things; wide blast radius on change. (dependency-cruiser) |
| `src/lib` | Fan-out Ce=17 across 19 modules | Depends on many things; wide blast radius on change. (dependency-cruiser) |
_No high-risk zones flagged this run._

## 5. Who to ask

Expand All @@ -79,12 +76,12 @@ Structural coupling and cycles live in `artifact-2-structure.md` and `graph/`.
- `src/lib/writer.ts` — 12 commits in window
- `README.md` — 9 commits in window
- `tests/writer.test.ts` — 9 commits in window
- `src/lib/config.ts` — 8 commits in window
- `context/map/artifact-1-territory.md` — 8 commits in window

## 7. Limitations — what this map does NOT say

- It is a map of **activity and structure over the last 12 months**, not of correctness or quality.
- Afferent coupling (Ca) from dependency-cruiser is unreliable without a fully installed toolchain (external/aliased imports go unresolved). Treat Ca as a lower bound.
- dependency-cruiser not runnable — coupling metrics skipped this run.
- Static import graph only. Runtime wiring (dynamic import, template refs, feature flags, codegen) is invisible here and is an `unknown`, not "no dependency".

---
Expand Down
67 changes: 57 additions & 10 deletions tests/api-content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { createHash, generateKeyPairSync, sign } from "node:crypto";
import {
fetchArtifact,
fetchCatalog,
fetchHealth,
fetchLesson,
Expand All @@ -35,10 +36,12 @@ const realFetch = globalThis.fetch;
const realApiBase = process.env["API_BASE_URL"];
const realKeyset = process.env["BUNDLE_PUBLIC_KEYSET"];
let requestedUrls: string[] = [];
let requestedInits: Array<RequestInit | undefined> = [];

function mockFetchOnce(body: string, init: { status?: number; headers?: Record<string, string> } = {}) {
globalThis.fetch = (async (url: string | URL) => {
globalThis.fetch = (async (url: string | URL, requestInit?: RequestInit) => {
requestedUrls.push(String(url));
requestedInits.push(requestInit);
return new Response(body, {
status: init.status ?? 200,
headers: { "content-type": "application/json", ...init.headers },
Expand Down Expand Up @@ -66,6 +69,7 @@ const signedHeaders = (body: string, keyId = TEST_KEY_ID) => ({

beforeEach(() => {
requestedUrls = [];
requestedInits = [];
process.env["API_BASE_URL"] = "http://localhost:8787";
process.env["BUNDLE_PUBLIC_KEYSET"] = JSON.stringify([
{ keyId: TEST_KEY_ID, publicKey: publicKeyDerB64 },
Expand Down Expand Up @@ -142,24 +146,67 @@ describe("fetchLesson signature verification", () => {
if (!result.ok) expect(result.code).toBe("signature_missing");
});

it("passes API error envelopes through without signature checks", async () => {
mockFetchOnce(JSON.stringify({ error: "no", code: "no_membership" }), { status: 403 });
it("passes API error envelopes through before checking partial signing headers", async () => {
mockFetchOnce(JSON.stringify({ error: "module_locked", code: "locked_now" }), {
status: 403,
headers: { "X-Bundle-Signature": "ignored-on-error" },
});
const result = await fetchLesson("10xdevs-3", "m1l1", "tok");
expect(result.ok).toBe(false);
if (!result.ok) expect(result.code).toBe("no_membership");
expect(result).toEqual({
ok: false,
status: 403,
code: "locked_now",
error: "This module is not available yet.",
payload: { error: "module_locked", code: "locked_now" },
});
});
});

// --- plain endpoints -----------------------------------------------------------

describe("fetchCatalog", () => {
it("hits the encoded catalog path and returns the payload", async () => {
const payload = { course: "10xdevs-3", modules: [], lessons: [] };
it("encodes the catalog path and forwards bearer token and caller signal", async () => {
const payload = { course: "course/alpha", modules: [], lessons: [] };
mockFetchOnce(JSON.stringify(payload));
const result = await fetchCatalog("10xdevs-3", "tok");
const controller = new AbortController();

const result = await fetchCatalog("course/alpha", "token-1", {
signal: controller.signal,
});

expect(result.ok).toBe(true);
if (result.ok) expect(result.data.course).toBe("10xdevs-3");
expect(requestedUrls[0]).toContain("/api/catalog/10xdevs-3");
if (result.ok) expect(result.data.course).toBe("course/alpha");
expect(requestedUrls[0]).toBe("http://localhost:8787/api/catalog/course%2Falpha");
expect(new Headers(requestedInits[0]?.headers).get("authorization")).toBe("Bearer token-1");
expect(requestedInits[0]?.signal).toBe(controller.signal);
});
});

describe("fetchArtifact", () => {
it("always serializes tool while omitting an empty optional language", async () => {
mockFetchOnce(JSON.stringify({ type: "prompts", name: "review", content: "Review it" }));

const result = await fetchArtifact(
"course/alpha",
"m1/l1",
"prompts/custom",
"review notes",
"",
"token-4",
{ lang: "" },
);

expect(requestedUrls[0]).toBe(
"http://localhost:8787/api/artifacts/course%2Falpha/m1%2Fl1/prompts%2Fcustom/review%20notes?tool=",
);
expect(result).toEqual({
ok: false,
status: 0,
code: "signature_missing",
error:
"Artifact is missing a signature. The API may be misconfigured or compromised. " +
"Do NOT use the content. Report this to the course team.",
});
});
});

Expand Down