Repository navigation
decisions: reconcile all areas #3765
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
migmartri
merged 6 commits into
chainloop-dev:main
from
migmartri:decisions-reconcile-2026-11-01
Nov 4, 2026
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
ce9a007
docs(decisions): add Current Decisions pages for five areas
migmartri b3b44ce
docs(decisions): use area-prefixed decision IDs
migmartri bf7e598
docs(decisions): check the written text against the specs and the code
migmartri 8b095e4
docs(decisions): record CAS-009, a fixed existence cache lifetime
migmartri a69a51a
docs(decisions): address the open review comments and fix the Not sho…
migmartri a2eae5a
docs(decisions): address the second review round
migmartri File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| <!-- | ||
| AGENT INSTRUCTIONS. Keep this comment. Read it before you change this file. | ||
|
|
||
| The br:eng-adr skill writes this page. Do not edit it by hand, and do not change it as part of other work. A person approves each change before the skill writes it, and the area owner reviews it in a PR. | ||
|
|
||
| Structure. The index (README.md) has the parts Areas (the area map), Relationships, Repository-wide decisions, Non-Confirmed, Superseded, and Open conflicts. An area page has the parts Language, Current decisions, Non-Confirmed, Superseded, and Open conflicts. Each decision is a "### <PFX>-NNN: <title>" entry with the choice, then the lines Why, Rejected, Deciders, Source, and Code. | ||
| - Current decisions and Repository-wide decisions: the rules that hold today. Follow them. The page holds only choices that a reader of the code would likely get wrong. It does not describe how the system works: for that, read the code or the specs. | ||
| - Non-Confirmed: decisions that the code does not show yet, for example a plan in a spec. They are not rules yet. | ||
| - Superseded: old decisions, struck through, each with the ID of the decision that replaced it. They are history only. | ||
| - Open conflicts: drift and disagreements that a person must settle. | ||
| - Language: the words of the area, and the words to avoid. | ||
|
|
||
| - Before you change the behavior of an area, read its current decisions and its Language. The page leaves out smaller decisions (the "Not shown" line), so also check the Decision Records of the specs that the page lists. Read the linked spec for the reasons. | ||
| - To record a decision that the team made and built: run br:eng-adr new. | ||
| - To change a decision, or to make one that is not built yet: write a spec with br:eng-spec. Its Decision Record entry says "replaces <PFX>-NNN". | ||
| - To refresh this page from the specs and the code: run br:eng-adr reconcile. | ||
| - Never renumber or reuse a decision ID. Never delete a decision: supersede it. | ||
| - When your code goes against a current decision, say so in your PR. Do not edit this page to match the code. | ||
| --> | ||
|
|
||
| # Current Decisions | ||
|
|
||
| > Written by `eng-adr`. To change a decision, write a spec or run `eng-adr new`. Do not edit this page by hand. | ||
|
|
||
| Last refresh: 2026-11-01, commit 4e150ca7. | ||
|
|
||
| ## Areas | ||
|
|
||
| ### Artifact CAS | ||
| - **Page:** [artifact-cas.md](artifact-cas.md) | ||
| - **Prefix:** CAS | ||
| - **Owner:** migmartri | ||
| - **Purpose:** Content-addressable storage of evidence blobs, with its upload and download paths and its caches. | ||
| - **Does not own:** the listeners, ports, TLS, and ingress of the CAS (Service Operations), and the download tokens that the control plane makes (Authentication). | ||
| - **Specs:** [issue-3543-cas-existence-cache](../specs/issue-3543-cas-existence-cache.md), [issue-3549-cas-download-browser-cache](../specs/issue-3549-cas-download-browser-cache.md) | ||
| - **Code:** `app/artifact-cas/`, `pkg/blobmanager/`, `pkg/cache/casexistence/`, `pkg/middlewares/http/` | ||
|
|
||
| ### Attestation Process | ||
| - **Page:** [attestation-process.md](attestation-process.md) | ||
| - **Prefix:** ATT | ||
| - **Owner:** migmartri | ||
| - **Purpose:** The attestation lifecycle of the CLI (`init`, `add`, `status`, `push`, `reset`, `verify`), and how it selects its organization and project. | ||
| - **Does not own:** AI coding session evidence (Chainloop Trace), and login and tokens (Authentication). | ||
| - **Specs:** [issue-3063-attestation-repo-config](../specs/issue-3063-attestation-repo-config.md) | ||
| - **Code:** `app/cli/cmd/attestation*.go`, `app/cli/pkg/action/attestation_*.go`, `app/cli/internal/repositoryconfig/`, `pkg/attestation/` | ||
|
|
||
| ### Authentication | ||
| - **Page:** [authentication.md](authentication.md) | ||
| - **Prefix:** AUT | ||
| - **Owner:** migmartri | ||
| - **Purpose:** User login through the control plane, the login callback, and the hand-off of the session token to the CLI and other clients. | ||
| - **Does not own:** the CAS download token header (Artifact CAS), and the organization that a command uses (Attestation Process). | ||
| - **Specs:** [issue-3626-login-code-exchange](../specs/issue-3626-login-code-exchange.md) | ||
| - **Code:** `app/controlplane/internal/service/auth.go`, `app/controlplane/pkg/biz/loginhandoff.go`, `app/controlplane/pkg/data/loginhandoff.go`, `app/cli/cmd/auth_login.go` | ||
|
|
||
| ### Service Operations | ||
| - **Page:** [service-operations.md](service-operations.md) | ||
| - **Prefix:** OPS | ||
| - **Owner:** migmartri | ||
| - **Purpose:** The network endpoints of the control plane and the CAS: listeners, protocols, TLS, internal ports, and the Helm chart ingress. | ||
| - **Does not own:** what the endpoints serve (Artifact CAS, Authentication). | ||
| - **Specs:** [issue-3628-single-endpoint](../specs/issue-3628-single-endpoint.md), [issue-3628-controlplane-http-dispatch](../specs/issue-3628-controlplane-http-dispatch.md) | ||
| - **Code:** `app/controlplane/internal/server/`, `app/artifact-cas/internal/server/`, `deployment/chainloop/` | ||
|
|
||
| ### Chainloop Trace | ||
| - **Page:** [chainloop-trace.md](chainloop-trace.md) | ||
| - **Prefix:** TRC | ||
| - **Owner:** jiparis | ||
| - **Purpose:** Recording AI coding sessions as evidence: providers, spec and skill capture, transcript pointers, line attribution, local mode, and the e2e test matrix. | ||
| - **Does not own:** the attestation lifecycle and the organization order of `.chainloop.yml` (Attestation Process), and blob storage (Artifact CAS). | ||
| - **Specs:** [issue-3495-session-spec-capture](../specs/issue-3495-session-spec-capture.md), [issue-3515-spec-capture-during-session](../specs/issue-3515-spec-capture-during-session.md), [issue-3520-pi-trace-provider](../specs/issue-3520-pi-trace-provider.md), [issue-3531-spec-source-role](../specs/issue-3531-spec-source-role.md), [issue-3540-trace-skills-used](../specs/issue-3540-trace-skills-used.md), [issue-3556-session-image-placeholders](../specs/issue-3556-session-image-placeholders.md), [issue-3561-up-to-date-local-spec-evidence](../specs/issue-3561-up-to-date-local-spec-evidence.md), [issue-3569-pasted-image-pointers](../specs/issue-3569-pasted-image-pointers.md), [issue-3582-trace-evidence-export](../specs/issue-3582-trace-evidence-export.md), [issue-3635-trace-e2e-matrix](../specs/issue-3635-trace-e2e-matrix.md), [issue-3639-line-ranges](../specs/issue-3639-line-ranges.md), [issue-3639-trace-line-attribution](../specs/issue-3639-trace-line-attribution.md), [issue-3657-codex-trace-provider](../specs/issue-3657-codex-trace-provider.md) | ||
| - **Code:** `app/cli/internal/trace/`, `app/cli/cmd/trace*.go`, `app/cli/pkg/action/trace_*.go`, `pkg/attestation/crafter/materials/aicodingsession/` | ||
|
|
||
| ## Relationships | ||
|
|
||
| - **Attestation Process → Chainloop Trace:** both read `.chainloop.yml` through one reader (ATT-003, attestation-process.md). A change to the file order or keys changes both areas. | ||
| - **Chainloop Trace → Artifact CAS:** On a push, Trace uploads each spec source, skill package, and pasted image as a material. Local mode uses neither. A transcript pointer replaces a copy only when its material is stored (TRC-016, chainloop-trace.md). | ||
| - **Service Operations → Artifact CAS, Authentication:** the shared endpoints carry the CAS ByteStream and download routes and the control plane login endpoints. A change to their dispatch affects all of them. It does not affect ByteStream traffic on the legacy gRPC listener of the CAS. That listener is on by default, and the chart sends the control plane connection to the CAS to it. The chart sets the TLS of both listeners from one secret. | ||
|
|
||
| ## Repository-wide decisions | ||
|
|
||
| None. | ||
|
|
||
| ## Non-Confirmed | ||
|
|
||
| None. | ||
|
|
||
| ## Superseded | ||
|
|
||
| None. | ||
|
|
||
| ## Open conflicts | ||
|
|
||
| None. | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| <!-- | ||
| AGENT INSTRUCTIONS. Keep this comment. Read it before you change this file. | ||
|
|
||
| The br:eng-adr skill writes this page. Do not edit it by hand, and do not change it as part of other work. A person approves each change before the skill writes it, and the area owner reviews it in a PR. | ||
|
|
||
| Structure. The index (README.md) has the parts Areas (the area map), Relationships, Repository-wide decisions, Non-Confirmed, Superseded, and Open conflicts. An area page has the parts Language, Current decisions, Non-Confirmed, Superseded, and Open conflicts. Each decision is a "### <PFX>-NNN: <title>" entry with the choice, then the lines Why, Rejected, Deciders, Source, and Code. | ||
| - Current decisions and Repository-wide decisions: the rules that hold today. Follow them. The page holds only choices that a reader of the code would likely get wrong. It does not describe how the system works: for that, read the code or the specs. | ||
| - Non-Confirmed: decisions that the code does not show yet, for example a plan in a spec. They are not rules yet. | ||
| - Superseded: old decisions, struck through, each with the ID of the decision that replaced it. They are history only. | ||
| - Open conflicts: drift and disagreements that a person must settle. | ||
| - Language: the words of the area, and the words to avoid. | ||
|
|
||
| - Before you change the behavior of an area, read its current decisions and its Language. The page leaves out smaller decisions (the "Not shown" line), so also check the Decision Records of the specs that the page lists. Read the linked spec for the reasons. | ||
| - To record a decision that the team made and built: run br:eng-adr new. | ||
| - To change a decision, or to make one that is not built yet: write a spec with br:eng-spec. Its Decision Record entry says "replaces <PFX>-NNN". | ||
| - To refresh this page from the specs and the code: run br:eng-adr reconcile. | ||
| - Never renumber or reuse a decision ID. Never delete a decision: supersede it. | ||
| - When your code goes against a current decision, say so in your PR. Do not edit this page to match the code. | ||
| --> | ||
|
|
||
| # Artifact CAS: Current Decisions | ||
|
|
||
| > Written by `eng-adr`. To change a decision, write a spec or run `eng-adr new`. Do not edit this page by hand. | ||
|
|
||
| **Purpose:** Content-addressable storage of evidence blobs, with its upload and download paths and its caches. **Owner:** migmartri. **Does not own:** the listeners, ports, TLS, and ingress of the CAS (Service Operations), and the download tokens that the control plane makes (Authentication). **Specs:** [issue-3543-cas-existence-cache](../specs/issue-3543-cas-existence-cache.md), [issue-3549-cas-download-browser-cache](../specs/issue-3549-cas-download-browser-cache.md). **Last refresh:** 2026-11-01, commit 4e150ca7. | ||
|
|
||
| ## Language | ||
|
|
||
| - **Existence cache**: the server-side cache of "this blob is in the backend" results, keyed per organization and backend. _Avoid_: "upload cache", because the cache holds no content. | ||
| - **Client cache**: the in-process cache of backend clients and their credentials. _Avoid_: "credentials cache", because the credentials are part of the client and never stored alone. | ||
|
|
||
| ## Current decisions | ||
|
|
||
| ### CAS-001: Existence cache in NATS KV when connected, in memory otherwise | ||
| The existence cache uses the shared cache library. It uses NATS KV when the CAS has a NATS connection. It uses an in-memory LRU when it has no connection, or when the NATS bucket cannot be set up at startup. A NATS failure at runtime is a cache miss, not a change to memory. | ||
| - Why: replicas share hits when NATS is there, and the CAS gets no new dependency when it is not. | ||
| - Rejected: memory only (the hit rate drops as replicas grow). NATS required (a hard dependency for a speed gain). | ||
| - Deciders: migmartri, javirln | ||
| - Source: [issue-3543-cas-existence-cache D-001](../specs/issue-3543-cas-existence-cache.md) | ||
| - Code: verified: `pkg/cache/casexistence/casexistence.go`, `app/artifact-cas/cmd/wire.go`. | ||
|
|
||
| ### CAS-002: The existence cache lives in the CAS, server side | ||
| The CAS ByteStream write checks the cache and answers "already exists" with no backend call. The CLI has no cache. | ||
| - Why: it works for all CLI versions and all clients, with no API change. | ||
| - Rejected: a cache in the CLI (each command is a new process, so nothing is reused). | ||
| - Deciders: migmartri, javirln | ||
| - Source: [issue-3543-cas-existence-cache D-003](../specs/issue-3543-cas-existence-cache.md) | ||
| - Code: verified: `app/artifact-cas/internal/service/bytestream.go`, `app/artifact-cas/internal/service/cache.go`. | ||
|
|
||
| ### CAS-003: The cache key starts with the organization | ||
| The key is the organization, then the backend type, then a hash of the secret reference, then the digest. The cache has its own bucket. | ||
| - Why: the organization prefix keeps the entries of one tenant away from all other tenants, also on shared storage. The secret reference separates backends in one organization. | ||
| - Rejected: the digest alone (the upload of one tenant answers for another tenant, and shows that the other tenant has the file). The backend and the digest without the organization (a shared backend leaks the same information). | ||
| - Deciders: migmartri, javirln | ||
| - Source: [issue-3543-cas-existence-cache D-004](../specs/issue-3543-cas-existence-cache.md) | ||
| - Code: verified: `pkg/cache/casexistence/casexistence.go`. `app/artifact-cas/internal/service/cache.go` skips the cache when the organization is empty. | ||
|
|
||
| ### CAS-004: Credentials never go to a shared store | ||
| The client cache, which holds backend credentials, stays in process memory. It never uses NATS. | ||
| - Why: credentials must not leave the process. | ||
| - Deciders: migmartri, javirln | ||
| - Source: [issue-3543-cas-existence-cache D-006](../specs/issue-3543-cas-existence-cache.md) | ||
| - Code: verified: `app/artifact-cas/internal/service/cache.go` (in-process expirable LRU). | ||
|
|
||
| ### CAS-005: Downloads use the browser HTTP cache | ||
| The HTTP download endpoint of the CAS sets cache headers and answers 304 when the browser has the content. ByteStream downloads do not change. The control plane keeps no copy of the bytes. | ||
| - Why: the browser downloads straight from the CAS, so a cache there skips the backend copy and the transfer. | ||
| - Rejected: a server cache in the control plane (the control plane never sees the bytes, and its message size limit is too small). | ||
| - Deciders: jiparis, migmartri | ||
| - Source: [issue-3549-cas-download-browser-cache D-001](../specs/issue-3549-cas-download-browser-cache.md) | ||
| - Code: verified: `app/artifact-cas/internal/service/download.go`. | ||
|
|
||
| ### CAS-006: The download token goes in the Authorization header | ||
| The CAS accepts the download token in an `Authorization: Bearer` header. When a client moves the token from the `?t=` query to this header, the download URL stays the same between calls. | ||
| - Why: the browser cache uses the URL as its key, and the token changes on each call. | ||
| - Rejected: one token for each user and digest (the URL stays the same only for the life of the token). | ||
| - Deciders: jiparis, migmartri | ||
| - Source: [issue-3549-cas-download-browser-cache D-003](../specs/issue-3549-cas-download-browser-cache.md) | ||
| - Code: verified on the CAS side: `pkg/middlewares/http/jwt.go`. When `cors.allow_origins` is set, the preflight in `app/artifact-cas/internal/server/cors.go` allows `Authorization`. The control plane `GetDownloadURL` still puts the token in `?t=` (`app/controlplane/internal/service/casredirect.go`). The client that moves the token to the header is not in this repository. | ||
|
|
||
| ### CAS-007: The header token wins, with no fallback to the query | ||
| When a request has a token in the header and in the query, the CAS uses only the header. A bad header fails with 401. | ||
| - Why: a client that sends a header sets its intent. | ||
| - Rejected: reject a request with both (the viewer must then strip the query). The query wins (the header has no effect for a URL that still holds a token). | ||
| - Deciders: jiparis, migmartri | ||
| - Source: [issue-3549-cas-download-browser-cache D-004](../specs/issue-3549-cas-download-browser-cache.md) | ||
| - Code: verified: `pkg/middlewares/http/jwt.go`. | ||
|
|
||
| ### CAS-008: The CAS checks that the object exists before a 304 | ||
| Before it answers 304, the CAS makes a metadata call to the backend. A deleted object gives 404. | ||
| - Why: a deleted object stops showing at once, and the metadata call is cheap. | ||
| - Rejected: a 304 from the digest alone (a browser can show a deleted object until it drops its copy). | ||
| - Deciders: jiparis, migmartri | ||
| - Source: [issue-3549-cas-download-browser-cache D-005](../specs/issue-3549-cas-download-browser-cache.md) | ||
| - Code: verified: `app/artifact-cas/internal/service/download.go`. | ||
|
|
||
| ### CAS-009: The existence cache lifetime is fixed, with no off switch | ||
| Replaces [issue-3543-cas-existence-cache D-007](../specs/issue-3543-cas-existence-cache.md) and the settings of R-004. An existence entry expires after 24 hours. No setting changes the lifetime or turns the cache off. | ||
| - Why: blobs cannot be deleted through Chainloop, so a fixed 24-hour bound covers the only risk. A setting adds configuration that no operator needs. | ||
| - Rejected: a configurable lifetime and an operator switch that turns the cache off (spec D-007 and R-004). | ||
| - Deciders: migmartri | ||
| - Source: recorded directly, 2026-11-03 | ||
| - Code: verified: `pkg/cache/casexistence/casexistence.go` (`ttl` constant), `app/artifact-cas/cmd/wire.go` (the cache is always on). | ||
|
|
||
| Not shown: 5 smaller or replaced decisions of [issue-3543-cas-existence-cache](../specs/issue-3543-cas-existence-cache.md), 2 of [issue-3549-cas-download-browser-cache](../specs/issue-3549-cas-download-browser-cache.md). | ||
|
migmartri marked this conversation as resolved.
Resolved
|
||
|
|
||
| ## Non-Confirmed | ||
|
|
||
| None. | ||
|
|
||
| ## Superseded | ||
|
|
||
| None. | ||
|
|
||
| ## Open conflicts | ||
|
|
||
| None. | ||
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.