Rename the project spec and update every reference to it

The charter file carried a tool-specific name while being the repository's own
document: mission, non-negotiable constraints, the pinned stack, repo
conventions and phase status, cited as authority by thirty files across the
agent, api, deploy, docs, search and terraform trees.

PROJECT-SPEC.md says what it is. All 42 references are updated in the same
commit, including the relative link in docs/status.md, so nothing points at a
filename that no longer exists.
This commit is contained in:
2026-08-28 15:57:12 -07:00
parent 25d5d9ce2e
commit f756a9d4f6
31 changed files with 41 additions and 41 deletions
View File
+1 -1
View File
@@ -211,7 +211,7 @@ escalation, not a footnote: think about whether your environment wants
the log-shipping agent running with that level of access before turning the log-shipping agent running with that level of access before turning
on the `etw` feature and an `[source] kind = "etw"` config. Event Log on the `etw` feature and an `[source] kind = "etw"` config. Event Log
alone (no elevated privileges needed) covers the common case and is what alone (no elevated privileges needed) covers the common case and is what
Phase 1's exit criteria in `/CLAUDE.md` actually requires to be running. Phase 1's exit criteria in `/PROJECT-SPEC.md` actually requires to be running.
Providers are configured by **GUID**, not friendly name — ETW's own API Providers are configured by **GUID**, not friendly name — ETW's own API
requires it. Look one up with `logman query providers "<Friendly Name>"`. requires it. Look one up with `logman query providers "<Friendly Name>"`.
+2 -2
View File
@@ -77,7 +77,7 @@ pub enum SourceConfig {
// Dead-code-on-default-build, same reasoning as EventLog/Etw below: // Dead-code-on-default-build, same reasoning as EventLog/Etw below:
// these fields are only read by the `file-tail`-gated arm in // these fields are only read by the `file-tail`-gated arm in
// spawn_source (main.rs), which doesn't exist in the default build // spawn_source (main.rs), which doesn't exist in the default build
// (`default = ["journald"]`). Pre-existing gap from Phase 0 — CLAUDE.md // (`default = ["journald"]`). Pre-existing gap from Phase 0 — PROJECT-SPEC.md
// mandates plain `cargo clippy --all-targets -- -D warnings` (no // mandates plain `cargo clippy --all-targets -- -D warnings` (no
// --all-features), which this broke silently since only // --all-features), which this broke silently since only
// --all-features clippy was ever actually run. // --all-features clippy was ever actually run.
@@ -202,7 +202,7 @@ impl Default for MetricsConfig {
/// way. Kept as a small hand-rolled parser rather than pulling in a /// way. Kept as a small hand-rolled parser rather than pulling in a
/// duration-parsing crate for this one field -- this is the /// duration-parsing crate for this one field -- this is the
/// statically-linked edge agent every "no glibc runtime deps" constraint /// statically-linked edge agent every "no glibc runtime deps" constraint
/// in CLAUDE.md is about keeping lean, and the grammar needed here is a /// in PROJECT-SPEC.md is about keeping lean, and the grammar needed here is a
/// handful of lines. /// handful of lines.
fn deserialize_duration<'de, D>(deserializer: D) -> Result<Duration, D::Error> fn deserialize_duration<'de, D>(deserializer: D) -> Result<Duration, D::Error>
where where
+1 -1
View File
@@ -9,7 +9,7 @@ and `/docs/query-language-reference.md` for the user-facing syntax.
## Why plain REST, not gRPC + REST gateway ## Why plain REST, not gRPC + REST gateway
CLAUDE.md pins the control plane to "Go, gRPC + REST gateway." This PROJECT-SPEC.md pins the control plane to "Go, gRPC + REST gateway." This
service is plain `net/http` instead — a deliberate simplification, not a service is plain `net/http` instead — a deliberate simplification, not a
change to the pinned stack. Wiring up a `.proto` service, change to the pinned stack. Wiring up a `.proto` service,
`google.api.http` annotations, and `protoc-gen-grpc-gateway` codegen for `google.api.http` annotations, and `protoc-gen-grpc-gateway` codegen for
+1 -1
View File
@@ -2,7 +2,7 @@
// login: a real login page and session-based auth covering both /api // login: a real login page and session-based auth covering both /api
// and /alerting, plus a simple admin-managed user list, for deployments // and /alerting, plus a simple admin-managed user list, for deployments
// reachable over the internet that can no longer rely on Phase 0-3's // reachable over the internet that can no longer rely on Phase 0-3's
// "no auth yet" default (see /docs/architecture.md and CLAUDE.md's // "no auth yet" default (see /docs/architecture.md and PROJECT-SPEC.md's
// Phase 4 section for the enterprise/ SSO alternative this is not -- // Phase 4 section for the enterprise/ SSO alternative this is not --
// this package has no tenant/RBAC-service concept, just "is this a // this package has no tenant/RBAC-service concept, just "is this a
// valid logged-in user"). // valid logged-in user").
+2 -2
View File
@@ -1,7 +1,7 @@
# deploy # deploy
Kubernetes deployment for Cairn OBS, added in Phase 4 (`/deploy` was Kubernetes deployment for Cairn OBS, added in Phase 4 (`/deploy` was
deliberately stubbed through Phase 3 -- see `/CLAUDE.md`'s Phase 3 deliberately stubbed through Phase 3 -- see `/PROJECT-SPEC.md`'s Phase 3
non-goals). Two pieces: non-goals). Two pieces:
- `operator/` -- a small Go controller-runtime Operator managing one CRD - `operator/` -- a small Go controller-runtime Operator managing one CRD
@@ -18,7 +18,7 @@ map of per-tenant ClickHouse connection pools via `internal/chrunner`;
`search` holds a map of per-tenant Tantivy indices via `search` holds a map of per-tenant Tantivy indices via
`src/registry.rs`) -- not at the Kubernetes layer. This directory is `src/registry.rs`) -- not at the Kubernetes layer. This directory is
**not** "one Deployment per tenant" or a general multi-cluster system; **not** "one Deployment per tenant" or a general multi-cluster system;
that's an explicit Phase 4 non-goal (see `/CLAUDE.md`). What it *does* that's an explicit Phase 4 non-goal (see `/PROJECT-SPEC.md`). What it *does*
add: add:
- A `Tenant` CRD + controller (`operator/internal/controller`) that - A `Tenant` CRD + controller (`operator/internal/controller`) that
+1 -1
View File
@@ -99,7 +99,7 @@ unconditional by design, no disable switch.
both tenants reached `status.phase: Active` with real credentials. both tenants reached `status.phase: Active` with real credentials.
This proves Phase 4's "two tenants... with their own users, roles, This proves Phase 4's "two tenants... with their own users, roles,
dashboards" exit criteria (`/CLAUDE.md`) end to end at the deployment- dashboards" exit criteria (`/PROJECT-SPEC.md`) end to end at the deployment-
topology layer: `-provision-tenant` (`enterprise/internal/ topology layer: `-provision-tenant` (`enterprise/internal/
tenantprovision`) is what actually creates each tenant's ClickHouse tenantprovision`) is what actually creates each tenant's ClickHouse
database/user/grant and marks it active in `rbacstore`; running inside database/user/grant and marks it active in `rbacstore`; running inside
+1 -1
View File
@@ -94,7 +94,7 @@ search:
# A second replica would form a second, independent consumer instance # A second replica would form a second, independent consumer instance
# against the same partitions with no coordination -- correctness, # against the same partitions with no coordination -- correctness,
# not just resource waste, is the reason this isn't a `replicas` knob # not just resource waste, is the reason this isn't a `replicas` knob
# yet. Matches CLAUDE.md's Phase 4 non-goal: "no general multi-cluster # yet. Matches PROJECT-SPEC.md's Phase 4 non-goal: "no general multi-cluster
# orchestration." # orchestration."
replicas: 1 replicas: 1
resources: {} resources: {}
+1 -1
View File
@@ -18,7 +18,7 @@ import (
// internal/controller/tenant_controller.go's doc comment for how // internal/controller/tenant_controller.go's doc comment for how
// TenantReconciler derives Phase/Conditions from those fields rather // TenantReconciler derives Phase/Conditions from those fields rather
// than fabricating its own "provisioned" claim. This is the "lightweight // than fabricating its own "provisioned" claim. This is the "lightweight
// unification" named in CLAUDE.md/docs/phase-4-runbook.md's "two // unification" named in PROJECT-SPEC.md/docs/phase-4-runbook.md's "two
// independent provisioning mechanisms" gap: -provision-tenant stays the // independent provisioning mechanisms" gap: -provision-tenant stays the
// real actor; this operator's reconcile loop never touches Postgres or // real actor; this operator's reconcile loop never touches Postgres or
// ClickHouse and gained no new credentials. // ClickHouse and gained no new credentials.
+5 -5
View File
@@ -65,7 +65,7 @@ one instead of deferring it, and keeps Kafka credentials off the edge agent.
family isn't a fit for this (no real row-level locking/transactional family isn't a fit for this (no real row-level locking/transactional
read-modify-write). read-modify-write).
This split is not to be changed without discussion — see CLAUDE.md. This split is not to be changed without discussion — see PROJECT-SPEC.md.
## Component responsibilities ## Component responsibilities
@@ -213,7 +213,7 @@ both the Helm and docker-compose layers, the two provisioning
mechanisms unified, both storage engines' write paths per-tenant-routed, mechanisms unified, both storage engines' write paths per-tenant-routed,
and the tenant-picker frontend page now built and browser-verified and the tenant-picker frontend page now built and browser-verified
(`web/src/routes/select-tenant`, `api/httpserver.WithCredentialedCORS` (`web/src/routes/select-tenant`, `api/httpserver.WithCredentialedCORS`
— see `/CLAUDE.md`'s Phase 4 section and `/web/README.md`'s "Tenant — see `/PROJECT-SPEC.md`'s Phase 4 section and `/web/README.md`'s "Tenant
picker" section), the remaining gaps in this phase are entirely the picker" section), the remaining gaps in this phase are entirely the
already-disclosed live-verification caveats: the ClickHouse/Postgres- already-disclosed live-verification caveats: the ClickHouse/Postgres-
backed pieces have never run against a real database in this backed pieces have never run against a real database in this
@@ -244,18 +244,18 @@ plain HTTP instead (`api/authz.HTTPAuthorizer`, `web`'s
`GET /auth/features`) — the same "network boundary, not import boundary" `GET /auth/features`) — the same "network boundary, not import boundary"
shape `/alerting``api` already used before `enterprise/` existed. shape `/alerting``api` already used before `enterprise/` existed.
## Non-negotiables carried from CLAUDE.md ## Non-negotiables carried from PROJECT-SPEC.md
- Rust agent: statically linked musl, `x86_64-unknown-linux-musl` and - Rust agent: statically linked musl, `x86_64-unknown-linux-musl` and
`aarch64-unknown-linux-musl`, no glibc runtime deps. `aarch64-unknown-linux-musl`, no glibc runtime deps.
- Windows support via native ETW/Event Log API, not WSL — designed - Windows support via native ETW/Event Log API, not WSL — designed
(Phase 1) but still unverified on real Windows hardware. (Phase 1) but still unverified on real Windows hardware.
- Every UI action maps to a documented REST/gRPC call — no UI-only logic. - Every UI action maps to a documented REST/gRPC call — no UI-only logic.
- Pinned stack (see CLAUDE.md table) — no substitutions without discussion. - Pinned stack (see PROJECT-SPEC.md table) — no substitutions without discussion.
## Explicitly out of scope (current, Phase 4) ## Explicitly out of scope (current, Phase 4)
Per `/CLAUDE.md`'s Phase 4 non-goals and `/docs/security/threat-model.md`: Per `/PROJECT-SPEC.md`'s Phase 4 non-goals and `/docs/security/threat-model.md`:
deny-override permission grants, a data retention/deletion policy for deny-override permission grants, a data retention/deletion policy for
deprovisioned tenants, general multi-cluster orchestration in `/deploy`, deprovisioned tenants, general multi-cluster orchestration in `/deploy`,
and any defense against a privileged ClickHouse/Postgres administrator — and any defense against a privileged ClickHouse/Postgres administrator —
+5 -5
View File
@@ -221,7 +221,7 @@ Key facts, verified against primary sources:
already speak. Real tradeoff: Redpanda was originally chosen partly already speak. Real tradeoff: Redpanda was originally chosen partly
for its lightweight single-binary footprint (`docker-compose.yml` for its lightweight single-binary footprint (`docker-compose.yml`
runs it with `--smp=1 --memory=1G --overprovisioned`, tuned for a runs it with `--smp=1 --memory=1G --overprovisioned`, tuned for a
resource-constrained local/homelab deployment per `CLAUDE.md`'s resource-constrained local/homelab deployment per `PROJECT-SPEC.md`'s
stated deployment targets); Kafka's JVM-based broker has a materially stated deployment targets); Kafka's JVM-based broker has a materially
larger minimum memory/startup footprint. This is a real regression larger minimum memory/startup footprint. This is a real regression
for the project's stated "docker-compose for local/homelab" use case, for the project's stated "docker-compose for local/homelab" use case,
@@ -263,7 +263,7 @@ project's own logo package.
**Before this audit**: no root `LICENSE` file existed anywhere in the **Before this audit**: no root `LICENSE` file existed anywhere in the
repo — not at the root, not in `enterprise/`. The only license repo — not at the root, not in `enterprise/`. The only license
declarations were prose statements in `CLAUDE.md`/`docs/architecture.md` declarations were prose statements in `PROJECT-SPEC.md`/`docs/architecture.md`
and correct `license = "AGPL-3.0-only"` fields in the two Rust and correct `license = "AGPL-3.0-only"` fields in the two Rust
workspaces' `Cargo.toml`s. `web/package.json` had no `license` field at workspaces' `Cargo.toml`s. `web/package.json` had no `license` field at
all (npm's tooling reported the package itself as `UNLICENSED` as a all (npm's tooling reported the package itself as `UNLICENSED` as a
@@ -324,10 +324,10 @@ assumed.
- Every prose reference to `enterprise/` as "commercial license" or - Every prose reference to `enterprise/` as "commercial license" or
"commercial-licensed" across the repo was updated. Present-tense "commercial-licensed" across the repo was updated. Present-tense
claims (code comments, `README.md` files describing current state, claims (code comments, `README.md` files describing current state,
`CLAUDE.md`'s non-negotiable constraints) were corrected outright. `PROJECT-SPEC.md`'s non-negotiable constraints) were corrected outright.
Historical, phase-specific documents (`docs/phase-4-isolation-design.md`, Historical, phase-specific documents (`docs/phase-4-isolation-design.md`,
`docs/phase-4-rbac-design.md`, `docs/phase-4-runbook.md`, and the `docs/phase-4-rbac-design.md`, `docs/phase-4-runbook.md`, and the
relevant parts of `CLAUDE.md`'s and `docs/architecture.md`'s Phase 4 relevant parts of `PROJECT-SPEC.md`'s and `docs/architecture.md`'s Phase 4
sections) were given forward-pointing corrections — "commercial sections) were given forward-pointing corrections — "commercial
license at the time this was written; AGPLv3 as of Phase 6" — rather license at the time this was written; AGPLv3 as of Phase 6" — rather
than rewritten as if the commercial-license period never happened, than rewritten as if the commercial-license period never happened,
@@ -400,7 +400,7 @@ Redpanda decision below, every item has one.
**Every task-2 (c)/unresolved-(b) item now has an explicit resolution** **Every task-2 (c)/unresolved-(b) item now has an explicit resolution**
— fixed, isolated, or, for Redpanda, flagged and decided. Phase 6's exit — fixed, isolated, or, for Redpanda, flagged and decided. Phase 6's exit
criteria in `CLAUDE.md` are updated accordingly. criteria in `PROJECT-SPEC.md` are updated accordingly.
## Legal disclaimer (repeated, deliberately) ## Legal disclaimer (repeated, deliberately)
+1 -1
View File
@@ -72,7 +72,7 @@ curl -X POST http://localhost:8080/search -H 'Content-Type: application/json' \
``` ```
**The `record_id` in both responses should match.** That's the actual **The `record_id` in both responses should match.** That's the actual
Phase 1 exit criterion (`/CLAUDE.md`) for the Linux half: the same Phase 1 exit criterion (`/PROJECT-SPEC.md`) for the Linux half: the same
record, reachable both ways. If `/search` returns nothing yet, give it a record, reachable both ways. If `/search` returns nothing yet, give it a
few more seconds — Tantivy commits on a timer (`COMMIT_INTERVAL_MS`, few more seconds — Tantivy commits on a timer (`COMMIT_INTERVAL_MS`,
default 2s), so there's a small window where a record is in ClickHouse default 2s), so there's a small window where a record is in ClickHouse
+1 -1
View File
@@ -97,7 +97,7 @@ not a projection):
| `SELECT count() FROM logs WHERE service='web'` (raw SQL) | Pure ClickHouse | 17.5ms | | `SELECT count() FROM logs WHERE service='web'` (raw SQL) | Pure ClickHouse | 17.5ms |
All four "well under a second" — the Phase 2 exit criteria in All four "well under a second" — the Phase 2 exit criteria in
`/CLAUDE.md`. The combined text+aggregation case (the one everyone should `/PROJECT-SPEC.md`. The combined text+aggregation case (the one everyone should
be nervous about, since it's a two-backend query) came in at 46ms, not be nervous about, since it's a two-backend query) came in at 46ms, not
meaningfully slower than the pure-ClickHouse case — the Tantivy prefilter meaningfully slower than the pure-ClickHouse case — the Tantivy prefilter
step is fast, and 5,000 UUIDs (see below) is a small `IN` clause by step is fast, and 5,000 UUIDs (see below) is a small `IN` clause by
+2 -2
View File
@@ -1,6 +1,6 @@
# Dashboard design # Dashboard design
> **Status:** Approved, in progress. Task 2 of Phase 3 — see `/CLAUDE.md`'s > **Status:** Approved, in progress. Task 2 of Phase 3 — see `/PROJECT-SPEC.md`'s
> "What done looks like for Phase 3" section for the exit criteria this is > "What done looks like for Phase 3" section for the exit criteria this is
> built against. Task 3 (dashboard CRUD API + web UI) implements this > built against. Task 3 (dashboard CRUD API + web UI) implements this
> doc; if implementation reveals this design is wrong somewhere, fix this > doc; if implementation reveals this design is wrong somewhere, fix this
@@ -24,7 +24,7 @@ saved query itself.
## Why not ClickHouse: PostgreSQL for control-plane config ## Why not ClickHouse: PostgreSQL for control-plane config
This phase adds PostgreSQL as a new pinned-stack component — flagged and This phase adds PostgreSQL as a new pinned-stack component — flagged and
confirmed with the project owner before implementation, per CLAUDE.md's confirmed with the project owner before implementation, per PROJECT-SPEC.md's
"ask before... making an architectural decision not already specified in "ask before... making an architectural decision not already specified in
`/docs/architecture.md`." Scope is strictly control-plane config `/docs/architecture.md`." Scope is strictly control-plane config
(dashboards, panels, and — per `/docs/phase-3-alerting-design.md` (dashboards, panels, and — per `/docs/phase-3-alerting-design.md`
+1 -1
View File
@@ -37,7 +37,7 @@ ships entirely in `enterprise/`, not AGPL core. Core (`/api`,
`/alerting`, `/web`) stays genuinely single-tenant: no multi-tenant `/alerting`, `/web`) stays genuinely single-tenant: no multi-tenant
mechanism present at all, not merely a missing management UI on top of mechanism present at all, not merely a missing management UI on top of
otherwise-functional isolation. This was an explicit choice put to the otherwise-functional isolation. This was an explicit choice put to the
project owner rather than assumed, because CLAUDE.md's licensing project owner rather than assumed, because PROJECT-SPEC.md's licensing
boundary text names multi-tenancy as enterprise-gated, and a boundary text names multi-tenancy as enterprise-gated, and a
"mechanism in core, feature in enterprise" split would have let a "mechanism in core, feature in enterprise" split would have let a
sufficiently motivated self-hosting AGPL user wire up real isolation sufficiently motivated self-hosting AGPL user wire up real isolation
+1 -1
View File
@@ -61,7 +61,7 @@ Design choices worth calling out explicitly:
| Hardware floor | Runs on CPU (slow) or a single consumer GPU via quantized (GGUF) models | Needs a real GPU; not practically CPU-viable | | Hardware floor | Runs on CPU (slow) or a single consumer GPU via quantized (GGUF) models | Needs a real GPU; not practically CPU-viable |
| Deployment complexity | Single binary/container, `ollama pull <model>`, built-in REST API | Python server, CUDA/driver management, more moving parts | | Deployment complexity | Single binary/container, `ollama pull <model>`, built-in REST API | Python server, CUDA/driver management, more moving parts |
| Throughput under concurrency | Adequate for one-user-at-a-time interactive use; not built for high concurrent QPS | Purpose-built for high-throughput serving (continuous batching, PagedAttention) | | Throughput under concurrency | Adequate for one-user-at-a-time interactive use; not built for high concurrent QPS | Purpose-built for high-throughput serving (continuous batching, PagedAttention) |
| Fit for this project | Matches `docker-compose for local/homelab` (CLAUDE.md's stated deployment target) — most self-hosters won't have a dedicated inference GPU | Fits a provisioned-GPU SaaS inference tier — not this phase's target (cloud is the opt-in secondary path, not primary) | | Fit for this project | Matches `docker-compose for local/homelab` (PROJECT-SPEC.md's stated deployment target) — most self-hosters won't have a dedicated inference GPU | Fits a provisioned-GPU SaaS inference tier — not this phase's target (cloud is the opt-in secondary path, not primary) |
Cairn OBS's actual AI workload shape is one interactive query bar per user Cairn OBS's actual AI workload shape is one interactive query bar per user
at a time, not a high-QPS inference-serving problem — vLLM's real at a time, not a high-QPS inference-serving problem — vLLM's real
+1 -1
View File
@@ -495,7 +495,7 @@ handler to call them from).
## Known residual risks (explicitly out of scope, not silently assumed away) ## Known residual risks (explicitly out of scope, not silently assumed away)
Per `/CLAUDE.md`'s Phase 4 non-goals, restated here in threat-model Per `/PROJECT-SPEC.md`'s Phase 4 non-goals, restated here in threat-model
terms: terms:
- **A privileged ClickHouse/Postgres administrator is not defended - **A privileged ClickHouse/Postgres administrator is not defended
+1 -1
View File
@@ -2,7 +2,7 @@
Phase-by-phase record of what was built, what "done" meant for each phase, Phase-by-phase record of what was built, what "done" meant for each phase,
and how it was verified. Conventions and constraints live in and how it was verified. Conventions and constraints live in
[`/CLAUDE.md`](../CLAUDE.md); the architecture spec is [`/PROJECT-SPEC.md`](../PROJECT-SPEC.md); the architecture spec is
[`/docs/architecture.md`](architecture.md). [`/docs/architecture.md`](architecture.md).
Each phase has a runbook in this directory recording the actual Each phase has a runbook in this directory recording the actual
+1 -1
View File
@@ -206,7 +206,7 @@ below) and Tantivy (`/search/README.md`'s "Per-tenant indices" section
routing (does traffic actually reach `enterprise-api` instead of routing (does traffic actually reach `enterprise-api` instead of
`api`), now a single-flag choice in both `deploy/helm/cairnobs` and `api`), now a single-flag choice in both `deploy/helm/cairnobs` and
`docker-compose.yml` (`enterprise.enabled` / `COMPOSE_PROFILES`), see `docker-compose.yml` (`enterprise.enabled` / `COMPOSE_PROFILES`), see
CLAUDE.md. PROJECT-SPEC.md.
## Ingest tenant identity ## Ingest tenant identity
+1 -1
View File
@@ -20,7 +20,7 @@
// Both Helm (deploy/helm/cairnobs/templates/api.yaml vs // Both Helm (deploy/helm/cairnobs/templates/api.yaml vs
// enterprise-api.yaml) and docker-compose.yml (COMPOSE_PROFILES) now // enterprise-api.yaml) and docker-compose.yml (COMPOSE_PROFILES) now
// make this the deployment-topology choice, not just a binary sitting // make this the deployment-topology choice, not just a binary sitting
// unused alongside api's -- see this repo's CLAUDE.md. `search`'s write // unused alongside api's -- see this repo's PROJECT-SPEC.md. `search`'s write
// side (ingest, and by extension the Redpanda consumer search itself // side (ingest, and by extension the Redpanda consumer search itself
// runs) is still not tenant-aware -- see enterprise/internal/searchclient // runs) is still not tenant-aware -- see enterprise/internal/searchclient
// and search/src/registry.rs's doc comments, and // and search/src/registry.rs's doc comments, and
+1 -1
View File
@@ -1,6 +1,6 @@
// Package tenantcrd syncs enterprise-api -provision-tenant's real // Package tenantcrd syncs enterprise-api -provision-tenant's real
// provisioning result into the Tenant CRD (deploy/operator/api/ // provisioning result into the Tenant CRD (deploy/operator/api/
// v1alpha1) -- the "lightweight unification" named in CLAUDE.md's "two // v1alpha1) -- the "lightweight unification" named in PROJECT-SPEC.md's "two
// independent provisioning mechanisms" gap: -provision-tenant stays the // independent provisioning mechanisms" gap: -provision-tenant stays the
// sole real actor (rbacstore + tenantprovision.ProvisionClickHouse, see // sole real actor (rbacstore + tenantprovision.ProvisionClickHouse, see
// runProvisionTenant's doc comment in cmd/enterprise-api/main.go); this // runProvisionTenant's doc comment in cmd/enterprise-api/main.go); this
+1 -1
View File
@@ -43,7 +43,7 @@ database, regardless of any `tenant_id` tag a message carries -- routing
a tagged record into its own tenant's dedicated database is a tagged record into its own tenant's dedicated database is
`enterprise/internal/chwriter` and `enterprise/cmd/enterprise-ingest`'s `enterprise/internal/chwriter` and `enterprise/cmd/enterprise-ingest`'s
job (a separate module by architectural convention, not a licensing job (a separate module by architectural convention, not a licensing
split -- both are AGPLv3, see `/CLAUDE.md`'s licensing boundary), not split -- both are AGPLv3, see `/PROJECT-SPEC.md`'s licensing boundary), not
this package's. `consumer` and `clickhousewriter` live outside this package's. `consumer` and `clickhousewriter` live outside
`internal/` (moved there once `enterprise/internal/chwriter` needed to `internal/` (moved there once `enterprise/internal/chwriter` needed to
import them directly -- Go's compiler-enforced `internal/` visibility import them directly -- Go's compiler-enforced `internal/` visibility
+1 -1
View File
@@ -9,7 +9,7 @@
// tenant the call's bearer credential belongs to and attaches it as a // tenant the call's bearer credential belongs to and attaches it as a
// "tenant_id" Kafka message header on every record produced -- the first // "tenant_id" Kafka message header on every record produced -- the first
// step of Phase 4's ingest tenant-awareness (see // step of Phase 4's ingest tenant-awareness (see
// /docs/phase-4-runbook.md and CLAUDE.md's "ingest itself has no tenant // /docs/phase-4-runbook.md and PROJECT-SPEC.md's "ingest itself has no tenant
// concept" gap). Deliberately scoped no further than that for now: // concept" gap). Deliberately scoped no further than that for now:
// nothing downstream (this package's own consumer, or `search`'s // nothing downstream (this package's own consumer, or `search`'s
// separate Redpanda consumer) reads that header yet to route a record's // separate Redpanda consumer) reads that header yet to route a record's
@@ -1,7 +1,7 @@
-- Additive-only per-resource grant: lets a specific user exceed their -- Additive-only per-resource grant: lets a specific user exceed their
-- tenant-baseline role on one dashboard (e.g. an Editor granted Admin on -- tenant-baseline role on one dashboard (e.g. an Editor granted Admin on
-- a dashboard they don't own). No deny-overrides -- named non-goal in -- a dashboard they don't own). No deny-overrides -- named non-goal in
-- /docs/phase-4-rbac-design.md and CLAUDE.md's Phase 4 exit criteria. -- /docs/phase-4-rbac-design.md and PROJECT-SPEC.md's Phase 4 exit criteria.
CREATE TABLE IF NOT EXISTS dashboard_permissions CREATE TABLE IF NOT EXISTS dashboard_permissions
( (
id UUID PRIMARY KEY, id UUID PRIMARY KEY,
+1 -1
View File
@@ -100,7 +100,7 @@ type LogRecord struct {
Severity Severity `protobuf:"varint,4,opt,name=severity,proto3,enum=sentry.logs.v1.Severity" json:"severity,omitempty"` Severity Severity `protobuf:"varint,4,opt,name=severity,proto3,enum=sentry.logs.v1.Severity" json:"severity,omitempty"`
// Original, unparsed log line. Always populated, even when structured // Original, unparsed log line. Always populated, even when structured
// fields below are also present, per the schema-on-read fallback // fields below are also present, per the schema-on-read fallback
// requirement in CLAUDE.md. // requirement in PROJECT-SPEC.md.
Message string `protobuf:"bytes,5,opt,name=message,proto3" json:"message,omitempty"` Message string `protobuf:"bytes,5,opt,name=message,proto3" json:"message,omitempty"`
// Structured fields extracted by the agent's parser (e.g. RFC 5424 // Structured fields extracted by the agent's parser (e.g. RFC 5424
// syslog header fields), plus source-provided fields (e.g. Windows // syslog header fields), plus source-provided fields (e.g. Windows
+1 -1
View File
@@ -43,7 +43,7 @@ message LogRecord {
// Original, unparsed log line. Always populated, even when structured // Original, unparsed log line. Always populated, even when structured
// fields below are also present, per the schema-on-read fallback // fields below are also present, per the schema-on-read fallback
// requirement in CLAUDE.md. // requirement in PROJECT-SPEC.md.
string message = 5; string message = 5;
// Structured fields extracted by the agent's parser (e.g. RFC 5424 // Structured fields extracted by the agent's parser (e.g. RFC 5424
+1 -1
View File
@@ -8,7 +8,7 @@ aggregation queries.
Tantivy is a Rust library with no maintained Go bindings — using it from Tantivy is a Rust library with no maintained Go bindings — using it from
`ingest` (Go) would mean cgo-bridging to a compiled Rust cdylib, exactly `ingest` (Go) would mean cgo-bridging to a compiled Rust cdylib, exactly
the fragile FFI complexity CLAUDE.md's "prefer boring, well-understood the fragile FFI complexity PROJECT-SPEC.md's "prefer boring, well-understood
dependencies... operators need to trust it" principle steers away from. dependencies... operators need to trust it" principle steers away from.
It would also couple ClickHouse-write latency to Tantivy-write latency in It would also couple ClickHouse-write latency to Tantivy-write latency in
the same request path. See `/docs/architecture.md` for the fuller the same request path. See `/docs/architecture.md` for the fuller
+1 -1
View File
@@ -76,7 +76,7 @@ no CVE, no known exploit, nothing to patch.
It reaches us only transitively (tantivy 0.22.1 -> measure_time 0.8.3 -> It reaches us only transitively (tantivy 0.22.1 -> measure_time 0.8.3 ->
instant 0.1.13), so it cannot be dropped without moving off the pinned instant 0.1.13), so it cannot be dropped without moving off the pinned
Tantivy version, and CLAUDE.md pins the stack deliberately. Tantivy version, and PROJECT-SPEC.md pins the stack deliberately.
The advisory's substance does not apply to this build either: `instant` The advisory's substance does not apply to this build either: `instant`
exists to paper over std::time::Instant being unavailable on wasm, and exists to paper over std::time::Instant being unavailable on wasm, and
+1 -1
View File
@@ -1,6 +1,6 @@
# terraform-provider-cairnobs # terraform-provider-cairnobs
Cairn OBS's Terraform provider -- `CLAUDE.md`'s "Repo conventions" section Cairn OBS's Terraform provider -- `PROJECT-SPEC.md`'s "Repo conventions" section
names this a first-class deliverable alongside `cairnobsctl` names this a first-class deliverable alongside `cairnobsctl`
("CLI and Terraform provider are first-class, not afterthoughts"), but ("CLI and Terraform provider are first-class, not afterthoughts"), but
no phase before this one had actually built any of it. Four resources no phase before this one had actually built any of it. Four resources
+1 -1
View File
@@ -2,7 +2,7 @@
// built on HashiCorp's terraform-plugin-framework (not the legacy // built on HashiCorp's terraform-plugin-framework (not the legacy
// SDKv2 -- the framework is the actively-developed, currently- // SDKv2 -- the framework is the actively-developed, currently-
// recommended library for a provider started from scratch, matching // recommended library for a provider started from scratch, matching
// CLAUDE.md's "prefer boring, well-understood dependencies" read // PROJECT-SPEC.md's "prefer boring, well-understood dependencies" read
// forward rather than backward). // forward rather than backward).
package provider package provider
+1 -1
View File
@@ -1,5 +1,5 @@
// Command terraform-provider-cairnobs is Cairn OBS's Terraform provider -- // Command terraform-provider-cairnobs is Cairn OBS's Terraform provider --
// CLAUDE.md names it a first-class deliverable alongside cairnobsctl // PROJECT-SPEC.md names it a first-class deliverable alongside cairnobsctl
// ("CLI and Terraform provider are first-class, not afterthoughts"), // ("CLI and Terraform provider are first-class, not afterthoughts"),
// but this is the first phase to actually build any of it. // but this is the first phase to actually build any of it.
// //