Skip to content

[EPIC] Establish single ownership of the Appwrite environment #26

Description

@Polichinel

The problem

The platform resolves Appwrite configuration through two mechanisms that both write to the same shared mutable state — the process environment — with no rule about which wins.

views-models/postprocessors/un_fao/run.sh sources .env (15 coordinates + 1 secret at lines 23-27), then exports registry values over the top (line 88). The registry wins because it runs second, not because anything says it should. Reorder those two blocks and the semantics invert silently.

Why this is correctness, not tidiness

Two prior reviews framed this as duplication and discoverability. A third, reading it through Rust's ownership model, found it meets a formal definition. Rust states three conditions for a data race, all of which must hold simultaneously:

Condition Here
Two or more pointers access the same data .env and the registry both name APPWRITE_ENDPOINT, *_BUCKET_ID, all 15
At least one is used to write both write
No mechanism synchronising access none. Statement order is the only discipline, and it is implicit

All three hold. This is not an analogy — it satisfies the definition.

Two related findings from the same lens:

  • A /blob/main/ reference is a dangling pointer. Rust: "a reference to a location that may have been given to someone else." views-datafactory's guides linked to main; §5.7 was struck; the reference silently began resolving to different rules. A pinned tag is a lifetime annotation; main is a raw pointer into mutable storage.
  • Clone must be visible. Rust does not forbid duplication — it forbids implicit duplication, because .clone() is "a visual indicator that something different is going on." The secret exists in four places and nothing marks any of them as a copy.

The contract already mandates the fix; the shell layer cannot express it

Seam contract §2:

Every library on this seam receives credentials as constructor parameters from the launching process and must never source, persist, default, or log them.

That is ownership and borrowing stated exactly: the launcher owns, libraries borrow, libraries never persist. views-postprocessing implements it correctly (it asserts rather than loads). Shell cannot comply — it has no parameter passing to child processes, only the global environment. That is why this defect class keeps recurring, and it is not a bug in any one file.

Desired end state

  • Exactly one writer per class of value. Registry owns coordinates. Operator owns the secret. A second writer errors rather than losing quietly.
  • No importable library loads a .env anywhere on the platform.
  • Registry resolution failure exits non-zero. No warn-and-continue.
  • A new machine is set up by running one script, which is tested in CI without real credentials.

Already shipped — verified against current HEADs, not assumed

Work Where State
find_dotenv() deleted; preflight on every Appwrite path; AppwriteConfig frozen views-pipeline-core#346 closed
C-231 metadata-delete fix views-faoapi#322 shipped in v1.4.0
Cache-partition salt views-faoapi#323 shipped in v1.4.0
Conformance vector views-appwrite#13 closed

Explicitly NOT this epic

  • Extracting shared client code into views-appwrite. That is views-faoapi#337, gated on þing-01 D8, which is views-appwrite#23. Those two are the same decision seen from opposite sides. Cross-linked, not re-scoped here.
  • The 131 run.sh files. They do not touch Appwrite — grep -ci appwrite returns 0. CRP: things not reused together should not be forced together. They get one marking line (S7) and nothing else.
  • The views-models rename; any secret-store design; views-pipeline-core#339's eviction phases.

Stories

# Story Repo Depends on
S1 Contract states the single-writer rule views-appwrite
S2 Registry resolution fails loud (C-47) views-models
S3 tools/platform_env.sh — one writer (C-48) views-models S1, S2
S4 The surviving library dotenv load at model_path.py:371 views-pipeline-core
S5 faoapi resolves coordinates from the registry views-faoapi S1
S6 Agreement check between the two registry readers (C-50) views-appwrite
S7 Mark the 131 generated run.sh as clones views-models
S8 bootstrap.sh, CI-testable without credentials views-models S2, S3
S9 Fill the dead [Internal Tech Guide]() link views-platform/docs S8
S10 views-crafdapi adopts the pattern at birth views-faoapi S5

Order: S1 · S2 · S4 · S6 · S7 (independent) → S3 → S5 → S8 → S9 · S10

S2 first among implementation items — it is the one most likely to break the machine being set up next.

Epic acceptance criteria

  • Exactly one writer per class of value; a second writer errors rather than losing silently
  • No importable library loads a .env anywhere on the platform
  • Registry resolution failure exits non-zero
  • views-faoapi's .env requires one variable
  • bootstrap.sh green in CI with no real credentials, and followed end-to-end on a machine that had never run the platform
  • The onboarding guide's technical pointer resolves
  • views-crafdapi never acquires a second .env habit
  • Both registry_to_env.py copies proven to emit identical output

Why this epic is homed here

The registry is homed in this repo and this is seam contract §4 territory. Most of the work lands in views-models and views-faoapi; this epic holds the shape, the ownership rule, and the acceptance criteria.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    epicLarge body of work broken into storiesplanningDecision or design work, no code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions