Day 1 scaffold: three-language monorepo, core-isolation rule, envelope pipeline, CI - #1
Merged
Conversation
Day-1 deliverable per PROJECT-PLAN.md §"Day 1".
- pnpm workspaces + turborepo at root; 21 TS packages (core, 11 adapters,
4 apps, 5 packages) each with package.json + tsconfig.json extending
tsconfig.base.json.
- TypeScript strict with path aliases @foxbook/core/*, @foxbook/adapters/*,
@foxbook/packages/*.
- Biome 2.x for format + lint; husky pre-commit wired to enforce biome,
typecheck, core-isolation, no-deskduck, and generated-types drift.
- Python via uv workspace: apps/scouts, apps/scrapers, adapters/crewai,
packages/sdk-py, packages/types-py — src-layout, hatchling build,
shared ruff config.
- Go 1.25 workspace for apps/log-daemon-go with main.go + main_test.go
(the test is non-trivial so go test ./... actually exercises the
toolchain — catches a broken CI job on day 1, not week 2).
No implementation code lands here; each package exports {} until its
feature is built.
…pipeline Day-1 deliverable per PROJECT-PLAN.md §"Day 1". core-isolation - core-isolation.config.json enumerates the enforcement surface: serviceAgnosticZones=[core/**, packages/**], adapterZone=adapters/*, explicit bannedImports + bannedCapabilityLiterals (no "etc."). - scripts/check-core-isolation.mjs enforces the structural boundary: service-agnostic zones cannot import adapters/* or banned identifiers, and cannot embed banned capability literals. Each adapters/<name>/ CAN and SHOULD import <name>, but cannot import sibling adapters. - Permanent fixtures in __fixtures__/core-isolation/ prove the checker works: 4 negative cases (core→adapter, core→banned, core capability literal, packages→banned — the sneak path) and 2 positive cases (adapter→own-lib, core→packages). @as-if-path hints let each fixture be evaluated as though it lived in its target zone. anti-DeskDuck - scripts/check-no-deskduck.mjs rejects "DeskDuck" in source files (.ts/.js/.py/.go), honoring LOCKED.md §17 "no DeskDuck code reuse." Foundation/decision docs and CLAUDE.md are exempt — those are legitimate prose references. envelope type pipeline - schemas/envelope/v1.json holds the firehose envelope as envelope_version: "1.0-draft" per foxbook-foundation.md §8.1.1. Content freezes day 7–9 when claim flow + Merkle log stabilize; the pipeline exists today. - scripts/generate-types.mjs emits packages/types-ts/src/envelope.ts (json-schema-to-typescript) and packages/types-py/src/foxbook_types/ envelope.py (quicktype). Hand-written barrels re-export. - scripts/check-generated.mjs regenerates and diffs against committed output — wired into CI + husky pre-commit. Schema/type drift can't slip past review.
Day-1 deliverable per PROJECT-PLAN.md §"Day 1".
- .github/workflows/ci.yml runs three jobs in parallel on push/PR:
node: pnpm install → biome check → typecheck → test →
check:core-isolation → check:no-deskduck → check:generated
python: uv sync → ruff → pytest
go: go vet → go test
No local `act` fallback — first PR push to GitHub is the real
validation gate for the workflow itself (act requires Docker and
matching runner images, yak-shaving for an empty scaffold).
- CODEOWNERS gives @cloakmaster required-review on rule-enforcement
surfaces: /core, /schemas, /adapters, /.github/workflows,
/scripts/check-*.mjs, /core-isolation.config.json, /docs/foundation/,
/docs/decisions/. Rule-enforcement files can't be weakened silently.
- .mcp.json (project-scoped via `claude mcp add --scope project`) wires
GitHub MCP + Context7 MCP so the config travels with the repo.
- .env.example lists day-1 local tokens (GITHUB_PERSONAL_ACCESS_TOKEN)
and commented-out day-2+ entries. Explicitly calls out that
SCOUT_WALLET_PRIVATE_KEY_* must NOT be injected as plaintext — that's
a week-2 security architecture decision.
…is canonical pnpm/action-setup@v4 rejects the combination of an explicit 'version: 10' step input and 'packageManager: pnpm@10.33.0' in package.json. Keep the packageManager field (it's the upstream source of truth and affects corepack) and let the action read from it.
3 tasks
cloakmaster
added a commit
that referenced
this pull request
Apr 21, 2026
Documents the service-agnostic core rule AFTER it was proven to bite on PR #1. Per the two-PR pattern: scaffold first (rule lands with proof of life via fixtures + green CI), then ADR documents verified behavior — never proposed behavior. Covers: - Why the rule exists (agent-tooling flux; DeskDuck lesson carried over) - What it enforces (structural boundary + ban list applied to both core/** and packages/**, closing the packages/shared sneak path) - How it's enforced (scripts/check-core-isolation.mjs; husky + CI) - How it's proven (permanent fixtures with @as-if-path hints) - Alternatives considered (interface injection, runtime registry, Biome GritQL plugin) - When it can be violated (only via a superseding ADR + sign-off; CODEOWNERS backs this) Co-authored-by: Ben <ben@inkog.io>
This was referenced Apr 22, 2026
cloakmaster
pushed a commit
that referenced
this pull request
Apr 30, 2026
"tried to claim a GitHub handle the caller didn't own" → "tried to claim someone else's GitHub handle" in DM #1 and DM #3. Same content, less stilted register. DM #2 unaffected (doesn't have this line). Final iteration. After CI green: squash-merge per the user's pre- authorization in the directive.
cloakmaster
added a commit
that referenced
this pull request
Apr 30, 2026
…43) * docs(distribution): outreach roster — 10 named targets, 3 DM drafts, post-redaction Day-8 distribution-motion PR (per the kickoff prompt). Replaces the TBD-slot placeholders with 10 verifiable named targets researched 2026-04-28 via GitHub commit history + GraphQL discussion API + public profile metadata. Citations per row. Roster (10 / 10 named): MCP team contacts (2): 1. David Soria Parra (@dsp-ant) — Anthropic, MCP Lead Maintainer. 2. Den Delimarsky (@localden) — Anthropic, MCP top contributor. A2A spec maintainers (2): 3. Holt Skinner (@holtskinner) — Google Cloud AI DA, top A2A contributor. 4. Darrel Miller (@darrelmiller) — Microsoft, A2A TSC member, IETF HTTPAPI WG Chair. Framework authors (4): 5. Nuno Campos (@nfcampos) — LangGraph maintainer. 6. João Moura (@joaomdmoura) — CrewAI founder. 7. Eric Zhu (@ekzhu) — AutoGen lead. 8. Abhi Aiyer (@abhiaiyer91) — Mastra CTO. Agent-security analyst voices (2): 9. Simon Willison (@simonw) — coined "lethal trifecta" for AI agent security. 10. Kwame Nyantakyi (@Kzino) — author of IETF draft-nyantakyi-vaip-agent-identity-01 + A2A Discussion #1752. Notable adjacent voice (no direct DM, engage via thread): @kenneives — author of A2A Discussion #1734 (Composable Trust Evidence Format, 97 comments) + AgentGraph product. Engagement happens via reply on the public RFC thread once we file ours. Strategic context section added: the 2026-04-28 web-research pass surfaced four pre-existing trust/identity discussions (#1631, #1720, #1734, #1752). Field is more crowded than PR #38's RFC text assumed. Foxbook's positioning has to be **upstream of trust scoring**, not in competition with it — verification primitive (cryptographic identity + log + revocation), with reputation/scoring layering above. PR #38's RFC text needs a Day-9 revision acknowledging #1734 + #1752 explicitly + naming the verification-primitive-vs-evidence-format split. Filed in references section. 3 DM drafts (one per major lane) embedded as code blocks under the roster, adapted from the base agent-hiring-gate framing per ADR 0006 §1 (offer-of-work-already-done, not request-for-attention): DM #1 (dsp-ant) — MCP angle; mentions Day-8 MCP server arriving + foxbookVerifyAgentCard wrapper. DM #2 (holtskinner) — A2A angle; explicitly references #1734 + #1752 + #1631 to position upstream-of-evidence- format; mentions filed Discussion. DM #3 (simonw) — security-analyst angle; references his own lethal- trifecta + MCP-prompt-injection writeups; mentions AgentGraph + #1734 + composability boundary. References to the adversarial-demo evidence file all use the post-redaction filename ops/evidence/2026-04-24-identity-guard- adversarial.md (chore/redact-third-party-handle PR #41 lands first; this branch will rebase post-merge if needed). Sending discipline rules + verifier_run leading-indicator definition + references section unchanged from PR #38's outreach.md scaffold. This PR is **drafted for review only** (per directive: "DO NOT merge yet — open as PR for my review"). DMs will be sent through Benjamin's accounts; the agent does not own the credentials and does not send. * docs(outreach): backfill A2A Discussion URL + correct license claim from MIT to Apache-2.0 Discussion filed 2026-04-29 at a2aproject/A2A#1803. Two changes in this commit: 1. Replaced two `[DISCUSSION_URL]` placeholders with the real URL: - DM #2 (Holt Skinner) body - References section 2. Corrected four occurrences of "MIT-licensed" → "Apache-2.0-licensed" in the DM templates. The repo's LICENSE is Apache 2.0 (committed in PR #45). Sending DMs to spec authors claiming the wrong license would have been a credibility hit caught here before send. DMs are now ready to send. Per the send-discipline rules (§Send- discipline rules, week-2 execution), each DM still requires hand- personalization to the target's published work + ~5 minute personalization cost. * docs(outreach): replace three DMs with tightened developer-to-developer versions Each DM cut from 215-247 words to 75-105 words. Drops: - "the runtime-safety wrapper", "discriminated outcomes by layer", "structurally precluding" — pitch-shaped jargon-stack - The closing "What blocks you from referencing this?" challenge — reads as cornering on a cold DM Adds: - Conversational close on each DM ("Worth a 5-min look?" / "what would you want to see different" / "what would?") — invites reply rather than demands justification - Canonical URL https://transparency.foxbook.dev (was workers.dev preview); leaf count "7 leaves" anchors live-state - Filed-Discussion URL a2aproject/A2A#1803 in each DM as the specific artifact landing Lead with concrete artifact + one piece of evidence + Discussion link + one inviting ask. Substance unchanged; register matches what cold outreach to senior engineers actually looks like. DMs ready to send once landing-page deploy is verified live in browser (PR #51 merged but Cloudflare deploy is Benjamin-side via `pnpm --filter @foxbook/transparency cf:deploy`). * docs(outreach): plain-language DM rewrites — drop spec-author vocabulary Iteration 5 on the three DMs. Substance unchanged; register shifted from "verification primitive" / "RFC-9162-shaped" / "fetchCount === 0" to plain English an engineer reads cold without slowing down. Phrases dropped: - "RFC-9162-shaped" — Certificate Transparency reference; gate-keeping on most readers, distracts even when known. - "(7 leaves)" — small Merkle-tree count, reads as "barely real" to anyone who parses it. - "fetchCount === 0" — code-speak in a cold DM; replaced with "the check refused at the source, before any Gist fetch happened" / "without fetching anything". - "path-segment owner check runs before any network I/O" — three jargon-blocks stacked. - "verification primitive" / "$ref" (in user-facing prose; kept in DM #2's specific spec ask where $ref is the actual concept being asked about) / "JSON-Schema interop" — spec-author vocabulary out of register for a cold DM. - "Apache 2.0" inline — kept only in DM #3 where Simon Willison's audience tracks open-source licensing for write-ups. Each DM now opens with what Foxbook does in plain English: "Built a public log + one-function check that verifies whether an agent's handle is really theirs before another agent calls it." Closes are inviting questions, not justification-demands: "5 min worth a look?" / "Worth a quick read?" / "what would?" * docs(outreach): conversational micro-tweak on adversarial-test phrasing "tried to claim a GitHub handle the caller didn't own" → "tried to claim someone else's GitHub handle" in DM #1 and DM #3. Same content, less stilted register. DM #2 unaffected (doesn't have this line). Final iteration. After CI green: squash-merge per the user's pre- authorization in the directive. --------- Co-authored-by: Ben <ben@inkog.io>
cloakmaster
added a commit
that referenced
this pull request
May 3, 2026
…or robustness (#42) Day-8 housekeeping for the two firehose observability findings flagged in PR #40's bench artifact (and the Day-7 close memory): 1. **postgres-js LISTEN dispatch wedge on bad-JSON callback (Finding #1).** On Day-7 the listener received exactly ONE notification with a malformed (non-JSON) payload, the decode_error logged, and every subsequent NOTIFY (valid or not) was silently dropped despite the underlying TCP connection staying alive. Verified at the time via pg_stat_activity: connection idle, application_name still 'foxbook-firehose-listener', dispatch wedged at the postgres-js library layer. Production triggers always emit valid row_to_json JSON, so this isn't a runtime risk today — but a future migration or future event type that emits something the listener can't parse would silently kill the firehose with no automatic recovery. **Defence:** opt-in self-test heartbeat. If `selfTestIntervalMs` is set (default 60s; 0 disables), the listener periodically fires its own `pg_notify` carrying a `__listener_self_test__` event_type with a fresh nonce. The listener's own onnotify handler recognizes the event_type, filters it from the public EventEmitter (SSE clients never see it), and updates `lastSelfTestEchoNonce`. On the next heartbeat tick, if the prior ping's nonce never echoed within `selfTestIntervalMs * 1.5` tolerance, the listener throws → forces the reconnect-backoff path → resubscribes. Sentinel log: firehose_listener_self_test_failed observed_lag=Nms expected_within=Mms Tested with 3 new cases: - Self-test ping fires + echoes cleanly → no reconnect, public emitter never sees the self-test event. - Self-test ping fires but never echoes → tolerance window elapses → `firehose_listener_self_test_failed` + reconnect + resubscribe (factory invoked twice). - aliveLogEveryHeartbeats=0 disables the periodic alive sentinel (clean-log surface for low-noise environments). 2. **Decode-error robustness.** The decode-error path already caught `JSON.parse` failures + sentinel-logged. Adding the comment that bytes were received successfully (dispatch is healthy at the postgres-js layer) so future-readers understand the wedge isn't from our parse failure — it was from postgres-js's internal state. No behaviour change; documentation only. 3. **Periodic alive sentinel (Finding #2 prep).** New `firehose_listener_alive heartbeats=N events=M self_tests_ok=K` log line, fired every `aliveLogEveryHeartbeats` heartbeats (default 10 → ~5 min at default heartbeat). Gives operators a positive-confirmation signal that the listener is live + how many events have flowed without needing to grep for the absence of reconnect logs. Counters reset on each (re)subscribe so the value is per-cycle, not lifetime. NOT included today (filed for follow-up if NOTICE-level visibility becomes load-bearing): postgres-js `onnotice` callback wiring. The library exposes this as a construction-time option on `postgres()`; threading it through `createDirectPostgresClient` would require a small factory-options extension. Doable, but `onnotice` only fires for Postgres NOTICE-level messages (e.g. raised by RAISE NOTICE), not connection-state transitions — which is what Finding #2 was actually asking for. The right defence for "silent library-level reconnect" is the self-test mechanism above (it catches the wedge regardless of what postgres-js's library-level state is doing); the `onnotice` debug callback would be a small additional visibility layer rather than a load-bearing fix. Verification (all green): * pnpm check:core-isolation * pnpm -r typecheck * pnpm --filter @foxbook/api test → 70 passed (3 new self-test cases) Implements the postgres-js LISTEN wedge defence + alive sentinel from the Day-7 close memory's "Day-8 queue". Co-authored-by: Ben <ben@inkog.io>
3 tasks
cloakmaster
added a commit
that referenced
this pull request
Jun 2, 2026
…93) (#94) * chore(lint): clear biome warnings + remove dead code, gate CI on warnings Drive the biome warning count to zero without changing behavior: - Export base64urlDecode from @foxbook/core and drop the byte-identical duplicate copy in apps/api/src/claim/handlers.ts (import from core). - Remove 2 dead biome-ignore comments in validators capability.test.ts and the dead eslint-disable in apps/api/src/firehose/listener.ts (the repo has no eslint, and the loop condition reads `stopped` so it was never a constant condition). - Scope lint/style/noNonNullAssertion off for TEST globs only (so test indexing bangs stop warning) — kept on for src, fixing the real src non-null assertions (sha256, jws, claim/repository, merkle-repository, smoke-test-revoke) with bounded `?? 0` / destructure-guard rewrites. - Apply the one safe useTemplate fix in claim.repository.test.ts. - Add --error-on-warnings to the biome step in CI so the count can't silently creep back up. Verification: `pnpm biome check --error-on-warnings` (clean, exit 0), `pnpm typecheck` (24/24), `pnpm --filter @foxbook/api test` (86 pass), `pnpm --filter @foxbook/core test` (59 pass), validators (72 pass), plus core-isolation / no-deskduck / generated pre-commit checks. * docs: fix doc inaccuracies (verifyAgentCard arity, firehose default, env vars, ADR count, 0007 header) - README hero + RFC + did:foxbook samples: add required asset_type to verifyAgentCard options - README: move firehose out of Live; it is disabled by default since #84 (FOXBOOK_FIREHOSE_ENABLED) - env-vars.md + .env.example: document FOXBOOK_FIREHOSE_ENABLED; .env.example adds DATABASE_URL_DIRECT + FOXBOOK_LOG_SIGNING_KEY_HEX, drops stale VERCEL_TOKEN/SENTRY_AUTH_TOKEN + Day-N prose - RATIONALE.md: ADR count eight->nine, add ADR 0009 line, fix misattributed 60s cache-policy sentence (API dynamic-state, not all read endpoints) - STATE-AT-STABLE-MODE-CLOSE.md: fix truncated Discussion #73 link - ADR 0007: add standard metadata block to match other ADRs * docs(spec): reconcile did:foxbook method spec to shipped code The did:foxbook method spec advertised behaviour the reference deployment does not implement. Filing to W3C as-is would describe a method that cannot be resolved. Downgrade the spec to describe what actually ships (no new endpoints — ADR 0008 freeze): - §1.1/§4.4/§6.2/§9: the signing path uses insertion-order canonical JSON (JSON.stringify semantics with caller-fixed key order; ADR 0005, core/src/crypto/canonical.ts, packages/db/src/merkle-repository.ts), NOT RFC 8785 JCS. The JCS canonicalizer in core/src/crypto/jcs.ts is a separate interop-only path, not used to sign leaves/STHs/JWS. Move RFC 8785 from Normative to Informative. Mirror the same fix in docs/specs/W3C-REGISTRY-SUBMISSION.md. - §3.2/§3.2.4/§7.1: there is no GET /agents/<did> resolver and no /.well-known/jwks.json. Rewrite resolution as a client-side projection over the real endpoints: /api/v1/claim/by-handle/..., /leaf/<index>, /inclusion/<index>, /root, and /.well-known/foxbook.json (where log_signing_public_key_hex lives). - §4.2: consistency proofs are GET /consistency?old=N&new=M (query params), not /consistency/<from>/<to> path segments. - §3.3/§3.4: rewrite the rotation and revocation leaf examples to match schemas/tl-leaf.v1.json exactly (signing-key-registration uses prior_ed25519_public_key_hex + new_ed25519_public_key_hex + recovery_key_signature + published_at, dropping previous_leaf_index; revocation uses revoked_key_hex + recovery_key_signature + revocation_timestamp + reason_code enum). - §2.1: relax the MSI ABNF/regex to ^did:foxbook:[0-9A-HJKMNP-TV-Z]{26}$ to match core/src/did.ts (the code does not enforce the [0-7] leading-character restriction). Fix the same regex in the W3C runbook. Docs only; no code change. * ops(uptime): split Neon-touching probes to */30 + document autosuspend as the #1 free-tier survival setting Reduce how often the uptime monitor wakes the free-tier Neon compute while keeping fast detection of a hard outage. uptime.yml: add a second cron so the static landing (no DB) keeps its */15 cadence while the two DB-backed probes (api/healthz, transparency/root) ride a slower */30 cron — roughly halving monitor-induced Neon wakeups. Each matrix entry is tagged with the cron it runs on; the probe step is gated via github.event.schedule so the off-schedule endpoints are skipped (and workflow_dispatch still probes everything). The 'Fail run if endpoint is down' behavior is unchanged: a skipped probe yields an empty outcome, so the fail step simply doesn't fire. OPERATIONS.md: in § 'Neon compute-hour exhaustion', make enabling Neon autosuspend / scale-to-zero the prominent #1 action (the Fly /health and uptime changes only reduce wakeups; they do nothing if the compute can never idle), add a one-line 'how to check current usage' pointer to the compute-hours graph, and restate that Launch ($19/mo) removes the cap entirely. Update the 'Uptime monitoring' runbook to describe the split schedule and the detection-latency tradeoff. * chore(ci): harden supply chain — dependabot, SHA-pinned actions, prod prune - add .github/dependabot.yml: weekly grouped minor/patch updates for npm (root), pip (pyproject), gomod (apps/log-daemon-go), and github-actions. - pin every workflow `uses:` to a 40-char commit SHA with a trailing # vX.Y.Z comment. superfly/flyctl-actions/setup-flyctl was on @master in the token-bearing deploy job — now pinned to ed8efb3 (v1.6). - add `permissions: { contents: read }` to deploy-api.yml (least privilege for the tag-gated Fly deploy). - bump vulnerable deps: hono ^4.12.23 (api + transparency), turbo ^2.9.16. - apps/api/Dockerfile: `pnpm prune --prod` after install to drop devDependencies from the prod image. tsx moved to @foxbook/api dependencies so it survives the prune — the container boots with `node --import tsx ./src/main.ts` and needs it at runtime. Guarded by a new prod-runtime-deps test. - ci.yml: non-blocking SCA step (`pnpm audit --audit-level=high || true`). * test(hardening): de-flake firehose sleeps + tier/consistency correctness fixes Mechanical test hardening plus two small correctness fixes (each TDD'd). Test hardening: - firehose.listener.test.ts: replace the three fixed setTimeout sleeps (the reconnect-sentinel and self-test-ping positive waits, and the alive-sentinel negative wait) with the existing poll-until pattern; the negative no-event assertion now uses fake timers so absence is deterministic. These fixed waits caused CI flakes in #62 and #64. - sdk-claim: add a drift guard (merkle-parity.test.ts) that runs every schemas/merkle-test-vectors.json inclusion vector through the inlined verifyInclusion (merkle-internal.ts), pinning it in lockstep with @foxbook/core (the vectors are core-generated ground truth). Correctness fixes: - core verifyConsistency: the m===0 branch accepted ANY oldRoot vacuously; now enforce bytesEqual(oldRoot, EMPTY_TREE_ROOT) so a forged zero-leaf root can't "prove" consistency. Added a negative vector. - claim/by-handle: tier2_pending (an unverified domain claim awaiting DNS/endpoint proof, app-state-only with no Merkle leaf) reported verification_tier 1; map it to 0. The tier>=1 leaf lookup now correctly skips it. Added handler + response-shape tests. Tooling: - add a .husky/pre-push hook running `pnpm test` (turbo-cached unit suite) so a red branch never leaves the machine. * fix(adapter-endpoint-challenge): SSRF guard on outbound fetch + per-IP claim rate limit The Tier-2 endpoint-challenge adapter fetched a claimant-supplied URL (apps/api/src/claim/body-schema.ts accepts endpoint_url) with no scheme or host validation. Reachable via two unauthenticated POSTs (/claim/start-domain then /claim/verify-endpoint), it was an SSRF primitive: point endpoint_url at cloud metadata (169.254.169.254), loopback, or RFC-1918/ULA internal services and read the JSON we round-trip. SSRF guard (two layers, sharing one isBlockedIp policy): 1. Pre-flight (guard.ts: assertOutboundAllowed) before any socket — https-only, then resolve the hostname and reject if ANY candidate IP is private/loopback/link-local/ULA/metadata (0.0.0.0, 127/8, 10/8, 172.16/12, 192.168/16, 169.254/16, ::1, ::, fc00::/7, fe80::/10, incl. IPv4-mapped v6). Bare IP literals are classified directly with no DNS. Fail-closed on resolver error. 2. Connect-time pin (node-transport.ts) — the default transport drives the request through node:https with a guarded dns.lookup that re-applies isBlockedIp to the exact address the socket is about to dial, closing the DNS-rebinding window between pre-flight and connect. Handles the all:true array shape so a private record in a multi-A response can't slip through. Redirects: redirect:"manual" + reject every 3xx (a Location can re-open the hole the pre-flight closed; a real challenge endpoint returns the JWS directly). The adapter's existing interface is unchanged; new optional EndpointVerifyOptions.resolveHostname lets tests drive the pre-flight deterministically, and the existing fetch seam is preserved. Rate limit (apps/api/src/claim/rate-limit.ts): per-IP in-memory token bucket on the mutating claim POST routes (keyed off Fly-Client-IP / X-Forwarded-For), 429 + Retry-After when empty. Blunts the amplification/abuse the outbound fetch enables. Per-instance by design (documented) — a coarse safety valve, not a distributed quota. The read-only GET /claim/by-handle is intentionally excluded. Tests: private/loopback/metadata + non-https targets rejected before any fetch; redirect to a private host blocked; connect-time guard blocks a loopback resolution (rebind defence); normal public https still round-trips (resolver/fetch mocked). Rate-limit: bucket math, per-IP isolation, refill, and the route 429 boundary. * docs(rationale): drop /api/v1/discover from Cache-Control list (sets none) * docs(ops): Neon autosuspend step references the 'main' branch (matches restore runbook) --------- Co-authored-by: Ben <ben@inkog.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Day-1 deliverable per
PROJECT-PLAN.md§"Day 1" and the revised plan at/Users/tester/.claude/plans/foxbook-claude-code-witty-hanrahan.md(approved before execution).Three commits on
bootstrap/day-1:main_test.go), strict TS with path aliases, Biome 2.x, husky pre-commit.core/**andpackages/**), anti-DeskDuck grep on source files, permanent positive + negative fixtures in__fixtures__/core-isolation/, envelope schema + type pipeline (TS viajson-schema-to-typescript, Python viaquicktype)..mcp.jsonwith GitHub + Context7 servers (project-scoped),.env.example,docs/operations/env-vars.md.Locked decisions honoured. Structural boundary + ban list both active.
packages/**is service-agnostic (closes thecore → packages/shared → x402sneak path). Negative fixtures prove the rule bites; positive fixtures prove it doesn't over-fire. Generated-types drift is enforced bypnpm check:generatedin CI AND husky pre-commit. Scout wallet key management deferred to week 2 with an explicit "do NOT inject plaintext keys" note indocs/operations/env-vars.md.ADR 0001 is deliberately a separate PR. The rule must prove itself on CI here first; the ADR then documents verified behaviour (not proposed behaviour). Do not consolidate to save time.
Test plan
CI is the validation gate — no local
actpretense. Expected green on all three matrix jobs:biome check,pnpm typecheck(21 packages),pnpm test(21 packages),check:core-isolation(fixture meta-tests + real scan),check:no-deskduck,check:generated(schema ↔ types drift)uv sync --all-packages --frozen,uv run ruff check,uv run pytest(1 bootstrap test asserts the workspace is importable)go vet ./...,go test ./...(assertsbanner()returns non-empty)After green + merge:
main: require PR, required status checks = {node, python, go}, CODEOWNERS review required, no force push.bootstrap/adr-0001(Phase 7).