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:
+1
-1
@@ -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
|
||||
on the `etw` feature and an `[source] kind = "etw"` config. Event Log
|
||||
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
|
||||
requires it. Look one up with `logman query providers "<Friendly Name>"`.
|
||||
|
||||
@@ -77,7 +77,7 @@ pub enum SourceConfig {
|
||||
// Dead-code-on-default-build, same reasoning as EventLog/Etw below:
|
||||
// these fields are only read by the `file-tail`-gated arm in
|
||||
// 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
|
||||
// --all-features), which this broke silently since only
|
||||
// --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
|
||||
/// duration-parsing crate for this one field -- this is the
|
||||
/// 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.
|
||||
fn deserialize_duration<'de, D>(deserializer: D) -> Result<Duration, D::Error>
|
||||
where
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ and `/docs/query-language-reference.md` for the user-facing syntax.
|
||||
|
||||
## 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
|
||||
change to the pinned stack. Wiring up a `.proto` service,
|
||||
`google.api.http` annotations, and `protoc-gen-grpc-gateway` codegen for
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// login: a real login page and session-based auth covering both /api
|
||||
// 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
|
||||
// "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 --
|
||||
// this package has no tenant/RBAC-service concept, just "is this a
|
||||
// valid logged-in user").
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
# deploy
|
||||
|
||||
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:
|
||||
|
||||
- `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
|
||||
`src/registry.rs`) -- not at the Kubernetes layer. This directory is
|
||||
**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:
|
||||
|
||||
- A `Tenant` CRD + controller (`operator/internal/controller`) that
|
||||
|
||||
@@ -99,7 +99,7 @@ unconditional by design, no disable switch.
|
||||
both tenants reached `status.phase: Active` with real credentials.
|
||||
|
||||
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/
|
||||
tenantprovision`) is what actually creates each tenant's ClickHouse
|
||||
database/user/grant and marks it active in `rbacstore`; running inside
|
||||
|
||||
@@ -94,7 +94,7 @@ search:
|
||||
# A second replica would form a second, independent consumer instance
|
||||
# against the same partitions with no coordination -- correctness,
|
||||
# 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."
|
||||
replicas: 1
|
||||
resources: {}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
// internal/controller/tenant_controller.go's doc comment for how
|
||||
// TenantReconciler derives Phase/Conditions from those fields rather
|
||||
// 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
|
||||
// real actor; this operator's reconcile loop never touches Postgres or
|
||||
// ClickHouse and gained no new credentials.
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
@@ -213,7 +213,7 @@ both the Helm and docker-compose layers, the two provisioning
|
||||
mechanisms unified, both storage engines' write paths per-tenant-routed,
|
||||
and the tenant-picker frontend page now built and browser-verified
|
||||
(`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
|
||||
already-disclosed live-verification caveats: the ClickHouse/Postgres-
|
||||
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"
|
||||
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
|
||||
`aarch64-unknown-linux-musl`, no glibc runtime deps.
|
||||
- Windows support via native ETW/Event Log API, not WSL — designed
|
||||
(Phase 1) but still unverified on real Windows hardware.
|
||||
- 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)
|
||||
|
||||
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
|
||||
deprovisioned tenants, general multi-cluster orchestration in `/deploy`,
|
||||
and any defense against a privileged ClickHouse/Postgres administrator —
|
||||
|
||||
@@ -221,7 +221,7 @@ Key facts, verified against primary sources:
|
||||
already speak. Real tradeoff: Redpanda was originally chosen partly
|
||||
for its lightweight single-binary footprint (`docker-compose.yml`
|
||||
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
|
||||
larger minimum memory/startup footprint. This is a real regression
|
||||
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
|
||||
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
|
||||
workspaces' `Cargo.toml`s. `web/package.json` had no `license` field at
|
||||
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
|
||||
"commercial-licensed" across the repo was updated. Present-tense
|
||||
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`,
|
||||
`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
|
||||
license at the time this was written; AGPLv3 as of Phase 6" — rather
|
||||
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**
|
||||
— 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)
|
||||
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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
|
||||
|
||||
@@ -97,7 +97,7 @@ not a projection):
|
||||
| `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
|
||||
`/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
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 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
|
||||
> built against. Task 3 (dashboard CRUD API + web UI) implements 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
|
||||
|
||||
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
|
||||
`/docs/architecture.md`." Scope is strictly control-plane config
|
||||
(dashboards, panels, and — per `/docs/phase-3-alerting-design.md` —
|
||||
|
||||
@@ -37,7 +37,7 @@ ships entirely in `enterprise/`, not AGPL core. Core (`/api`,
|
||||
`/alerting`, `/web`) stays genuinely single-tenant: no multi-tenant
|
||||
mechanism present at all, not merely a missing management UI on top of
|
||||
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
|
||||
"mechanism in core, feature in enterprise" split would have let a
|
||||
sufficiently motivated self-hosting AGPL user wire up real isolation
|
||||
|
||||
@@ -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 |
|
||||
| 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) |
|
||||
| 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
|
||||
at a time, not a high-QPS inference-serving problem — vLLM's real
|
||||
|
||||
@@ -495,7 +495,7 @@ handler to call them from).
|
||||
|
||||
## 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:
|
||||
|
||||
- **A privileged ClickHouse/Postgres administrator is not defended
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
Phase-by-phase record of what was built, what "done" meant for each phase,
|
||||
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).
|
||||
|
||||
Each phase has a runbook in this directory recording the actual
|
||||
|
||||
@@ -206,7 +206,7 @@ below) and Tantivy (`/search/README.md`'s "Per-tenant indices" section
|
||||
routing (does traffic actually reach `enterprise-api` instead of
|
||||
`api`), now a single-flag choice in both `deploy/helm/cairnobs` and
|
||||
`docker-compose.yml` (`enterprise.enabled` / `COMPOSE_PROFILES`), see
|
||||
CLAUDE.md.
|
||||
PROJECT-SPEC.md.
|
||||
|
||||
## Ingest tenant identity
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// Both Helm (deploy/helm/cairnobs/templates/api.yaml vs
|
||||
// enterprise-api.yaml) and docker-compose.yml (COMPOSE_PROFILES) now
|
||||
// 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
|
||||
// runs) is still not tenant-aware -- see enterprise/internal/searchclient
|
||||
// and search/src/registry.rs's doc comments, and
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package tenantcrd syncs enterprise-api -provision-tenant's real
|
||||
// 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
|
||||
// sole real actor (rbacstore + tenantprovision.ProvisionClickHouse, see
|
||||
// runProvisionTenant's doc comment in cmd/enterprise-api/main.go); this
|
||||
|
||||
+1
-1
@@ -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
|
||||
`enterprise/internal/chwriter` and `enterprise/cmd/enterprise-ingest`'s
|
||||
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
|
||||
`internal/` (moved there once `enterprise/internal/chwriter` needed to
|
||||
import them directly -- Go's compiler-enforced `internal/` visibility
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// tenant the call's bearer credential belongs to and attaches it as a
|
||||
// "tenant_id" Kafka message header on every record produced -- the first
|
||||
// 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:
|
||||
// nothing downstream (this package's own consumer, or `search`'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
|
||||
-- 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
|
||||
-- /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
|
||||
(
|
||||
id UUID PRIMARY KEY,
|
||||
|
||||
@@ -100,7 +100,7 @@ type LogRecord struct {
|
||||
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
|
||||
// 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"`
|
||||
// Structured fields extracted by the agent's parser (e.g. RFC 5424
|
||||
// syslog header fields), plus source-provided fields (e.g. Windows
|
||||
|
||||
@@ -43,7 +43,7 @@ message LogRecord {
|
||||
|
||||
// Original, unparsed log line. Always populated, even when structured
|
||||
// fields below are also present, per the schema-on-read fallback
|
||||
// requirement in CLAUDE.md.
|
||||
// requirement in PROJECT-SPEC.md.
|
||||
string message = 5;
|
||||
|
||||
// Structured fields extracted by the agent's parser (e.g. RFC 5424
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ aggregation queries.
|
||||
|
||||
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
|
||||
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.
|
||||
It would also couple ClickHouse-write latency to Tantivy-write latency in
|
||||
the same request path. See `/docs/architecture.md` for the fuller
|
||||
|
||||
+1
-1
@@ -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 ->
|
||||
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`
|
||||
exists to paper over std::time::Instant being unavailable on wasm, and
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# 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`
|
||||
("CLI and Terraform provider are first-class, not afterthoughts"), but
|
||||
no phase before this one had actually built any of it. Four resources
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// built on HashiCorp's terraform-plugin-framework (not the legacy
|
||||
// SDKv2 -- the framework is the actively-developed, currently-
|
||||
// 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).
|
||||
package provider
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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"),
|
||||
// but this is the first phase to actually build any of it.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user