trailsign 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trailsign-0.1.0/.github/workflows/publish.yml +20 -0
- trailsign-0.1.0/.github/workflows/test.yml +21 -0
- trailsign-0.1.0/.gitignore +13 -0
- trailsign-0.1.0/CLAUDE.md +81 -0
- trailsign-0.1.0/LICENSE +21 -0
- trailsign-0.1.0/PKG-INFO +134 -0
- trailsign-0.1.0/README.md +96 -0
- trailsign-0.1.0/docs/design.md +432 -0
- trailsign-0.1.0/pyproject.toml +37 -0
- trailsign-0.1.0/src/trailsign/__init__.py +24 -0
- trailsign-0.1.0/src/trailsign/settings.py +185 -0
- trailsign-0.1.0/tests/conftest.py +67 -0
- trailsign-0.1.0/tests/test_credential_source.py +14 -0
- trailsign-0.1.0/tests/test_resolved.py +77 -0
- trailsign-0.1.0/tests/test_resolvers.py +117 -0
- trailsign-0.1.0/tests/test_validate.py +35 -0
- trailsign-0.1.0/tools/verify_oracle_vault.py +64 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write # required for PyPI Trusted Publishing (OIDC) -- no API token stored
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.13"
|
|
18
|
+
- run: pip install build
|
|
19
|
+
- run: python -m build
|
|
20
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.13"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
- run: pip install -e ".[test]"
|
|
21
|
+
- run: pytest -v
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.pyc
|
|
3
|
+
.pytest_cache/
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.venv/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
|
|
9
|
+
# Local-only infrastructure notes (real IPs, SSH key paths, live OCIDs) --
|
|
10
|
+
# must NEVER be committed. See tools/verify_oracle_vault.py, which reads
|
|
11
|
+
# only from CLI args/env, never from this file directly, and stays
|
|
12
|
+
# secret-free so it's safe to commit.
|
|
13
|
+
local-infra/
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Guidance for Claude Code working in this repo. Kept short — detail
|
|
4
|
+
lives in `docs/design.md` and `README.md`, not here.
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
Trailsign is a small, language-independent library for resolving
|
|
9
|
+
application settings from a declarative, self-describing config, where
|
|
10
|
+
each value declares its own source (a literal, an environment variable,
|
|
11
|
+
a vault secret, ...) instead of the caller assuming where to look.
|
|
12
|
+
**Python package built out as of 2026-09-01** — `src/trailsign/` is a
|
|
13
|
+
real installable package (`pyproject.toml`, src layout) with a test
|
|
14
|
+
suite (`tests/`). MIT licensed, public on GitHub
|
|
15
|
+
(https://github.com/nankma/trailsign), CI (`.github/workflows/test.yml`)
|
|
16
|
+
runs on push/PR, `main` requires a passing PR before merge. A
|
|
17
|
+
`.github/workflows/publish.yml` exists for PyPI Trusted Publishing but
|
|
18
|
+
the project hasn't been published there yet — see "Immediate next
|
|
19
|
+
work". A port to a second language is the other remaining open work.
|
|
20
|
+
|
|
21
|
+
Extracted from a Telegram news-trend bot (Auguring, formerly Argus)
|
|
22
|
+
where this design started — see `docs/design.md`'s own "Origin" section
|
|
23
|
+
for why it moved here instead of staying bot-specific.
|
|
24
|
+
|
|
25
|
+
## Landmines
|
|
26
|
+
|
|
27
|
+
- **`trailsign-resolve:` is the only dispatch key — never rename it back
|
|
28
|
+
to a bare `resolve`, and never let it collide with `type:` or any
|
|
29
|
+
other field.** Two real bugs already happened this way (an overloaded
|
|
30
|
+
`type:` field, then a plain `resolve:` that was still a generic
|
|
31
|
+
collision risk) before landing here — see `docs/design.md`'s "Fixing
|
|
32
|
+
an ambiguity" section before touching the dispatch key.
|
|
33
|
+
- **This library never constructs consumer objects, only resolves values
|
|
34
|
+
to plain data.** Turning a resolved config block into a live object
|
|
35
|
+
(an adaptor, a client, anything) is always the *consumer's* own
|
|
36
|
+
factory, never this library's job — see `docs/design.md`'s "Two jobs,
|
|
37
|
+
two owners" section. Don't add object-construction here even if it
|
|
38
|
+
seems convenient for a first real consumer.
|
|
39
|
+
- **`OracleKeyVaultResolver` uses instance-principal auth
|
|
40
|
+
(`_oci_secrets_client()` in `src/trailsign/settings.py`) — not a
|
|
41
|
+
static config file, not an explicit key.** Verified 2026-09-01 against
|
|
42
|
+
a real OCI Vault secret from a compute instance (see
|
|
43
|
+
`tools/verify_oracle_vault.py`); only works from inside an OCI compute
|
|
44
|
+
instance (requires a dynamic-group IAM policy granting `read
|
|
45
|
+
secret-bundles` — a real gap hit during that verification, not a code
|
|
46
|
+
bug). `credential_sources`' `region`/`vault_ocid`/`compartment_ocid`
|
|
47
|
+
fields are validated to exist via `source:` but are **not** actually
|
|
48
|
+
consumed by this auth shape — don't assume they're load-bearing if
|
|
49
|
+
refactoring this resolver; see `docs/design.md`'s correction note
|
|
50
|
+
under "The converged design".
|
|
51
|
+
- **`OracleKeyVaultResolver.resolve()` validates the node's own fields
|
|
52
|
+
(`source`, `secret_ocid`) *before* `import oci`.** This was a real bug
|
|
53
|
+
found while writing tests: `import oci` used to run first, so a
|
|
54
|
+
missing `secret_ocid` raised `ModuleNotFoundError` instead of
|
|
55
|
+
`SettingsError` whenever the `oci` package wasn't installed — breaking
|
|
56
|
+
the "no oci dependency needed unless actually used" guarantee for the
|
|
57
|
+
validation-error paths, not just the happy path. Keep the import after
|
|
58
|
+
field validation if this method is touched again.
|
|
59
|
+
- **Secret hygiene**: never commit real infrastructure values (VM IPs,
|
|
60
|
+
SSH key paths, live OCIDs). `local-infra/infrastructure.yaml` holds
|
|
61
|
+
them and is gitignored; `tools/verify_oracle_vault.py` takes everything
|
|
62
|
+
sensitive via CLI arg only and stays secret-free so it's safe to
|
|
63
|
+
commit. Before this repo ever goes from private to public, run the
|
|
64
|
+
global `audit-before-going-public` skill first.
|
|
65
|
+
|
|
66
|
+
## Where to look
|
|
67
|
+
|
|
68
|
+
| Need | Where |
|
|
69
|
+
|---|---|
|
|
70
|
+
| Full design: data flow, diagrams, resolved/still-open questions | `docs/design.md` |
|
|
71
|
+
| Python reference implementation | `src/trailsign/settings.py` |
|
|
72
|
+
| Test suite | `tests/` (`conftest.py` has the shared fixture config) |
|
|
73
|
+
| Project status, what's built vs. not | `README.md` |
|
|
74
|
+
| How to write/extend design docs like `docs/design.md` | the `writing-system-design-docs` skill (global, not repo-local) |
|
|
75
|
+
|
|
76
|
+
## Immediate next work
|
|
77
|
+
|
|
78
|
+
Not built yet, in rough order:
|
|
79
|
+
1. First PyPI publish: register the pending Trusted Publisher on pypi.org (Owner `nankma`, repo `trailsign`, workflow `publish.yml`, environment `pypi` — see `.github/workflows/publish.yml`), then cut a GitHub Release to trigger it
|
|
80
|
+
2. Resolve `docs/design.md`'s remaining "Still open" items as they come up in practice, not speculatively (a non-instance-principal OCI auth shape, for consumers running outside an OCI compute instance, is the main one left)
|
|
81
|
+
3. Consider a port to a second language now that the Python package is solid, since the whole design's point is being language-independent, not just Python
|
trailsign-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nankang Ma
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
trailsign-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: trailsign
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Resolves a declarative, self-describing config into plain values
|
|
5
|
+
Project-URL: Homepage, https://github.com/nankma/trailsign
|
|
6
|
+
Project-URL: Repository, https://github.com/nankma/trailsign
|
|
7
|
+
Author-email: Nankang Ma <jjkkma@gmail.com>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 Nankang Ma
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
31
|
+
Classifier: Operating System :: OS Independent
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Requires-Python: >=3.10
|
|
34
|
+
Requires-Dist: pyyaml>=6.0
|
|
35
|
+
Provides-Extra: test
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == 'test'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# Trailsign
|
|
40
|
+
|
|
41
|
+
A small, language-independent library for resolving application
|
|
42
|
+
settings from a declarative, self-describing config — where each value
|
|
43
|
+
states its own source (a literal, an environment variable, a vault
|
|
44
|
+
secret, ...) instead of the calling code assuming where to look.
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
api-key:
|
|
48
|
+
trailsign-resolve: environment-variable
|
|
49
|
+
name: GNEWS_API_KEY
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`trailsign-resolve:` is a reserved, namespaced key — deliberately not a
|
|
53
|
+
bare word like `resolve` — so it can never collide with a consuming
|
|
54
|
+
project's own field names. It dispatches to a pluggable resolver;
|
|
55
|
+
whatever it resolves to is handed to the consumer as a plain value, with
|
|
56
|
+
no trace of where it came from left in the shape.
|
|
57
|
+
|
|
58
|
+
## Status
|
|
59
|
+
|
|
60
|
+
**Python package built out, as of 2026-09-01.** `src/trailsign/` is a
|
|
61
|
+
real installable package (`pyproject.toml`, src layout) with a test
|
|
62
|
+
suite covering the resolve walk, the three built-in resolvers
|
|
63
|
+
(`OracleKeyVaultResolver` verified against a real OCI Vault secret —
|
|
64
|
+
see `tools/verify_oracle_vault.py`), `validate()`'s combined-error
|
|
65
|
+
behavior, and the `trailsign-resolve` vs. `type` non-collision
|
|
66
|
+
regression. MIT licensed (see `LICENSE`). Public on GitHub; CI runs the
|
|
67
|
+
test suite on every push/PR. Not yet published to PyPI. A port to at
|
|
68
|
+
least one other language is still open, since the design's whole point
|
|
69
|
+
is being language-independent, not just Python.
|
|
70
|
+
|
|
71
|
+
### Installing it
|
|
72
|
+
|
|
73
|
+
Not on PyPI yet — until then, install straight from GitHub, ideally
|
|
74
|
+
pinned to a tag once one exists:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
pip install git+https://github.com/nankma/trailsign.git@main
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Install for development on this repo: `pip install -e ".[test]"`, then
|
|
81
|
+
`pytest`.
|
|
82
|
+
|
|
83
|
+
## Start here
|
|
84
|
+
|
|
85
|
+
- [`docs/design.md`](docs/design.md) — the core design: the config
|
|
86
|
+
shape, the resolve/dispatch contract (holds equally for a Go
|
|
87
|
+
`interface`, a Rust `trait`, or a Python `typing.Protocol`), why it's
|
|
88
|
+
shaped this way, two worked examples with diagrams, and what's still
|
|
89
|
+
undecided.
|
|
90
|
+
- [`src/trailsign/settings.py`](src/trailsign/settings.py) — the Python
|
|
91
|
+
reference implementation, matching `docs/design.md` exactly.
|
|
92
|
+
- [`tests/`](tests/) — the test suite; `tests/conftest.py` has a shared
|
|
93
|
+
fixture config mirroring `docs/design.md`'s worked examples.
|
|
94
|
+
- the `writing-system-design-docs` skill (global, not repo-local) — the
|
|
95
|
+
doc-writing convention `docs/design.md` follows, carried over
|
|
96
|
+
from where this project started in case future design docs here want
|
|
97
|
+
the same discipline (language-independent contracts, diagrams, a
|
|
98
|
+
"still open" section that's actually kept honest).
|
|
99
|
+
|
|
100
|
+
## Origin
|
|
101
|
+
|
|
102
|
+
This design started inside a Telegram news-trend bot (Auguring, formerly
|
|
103
|
+
Argus) while building a settings abstraction so that bot could run
|
|
104
|
+
standalone as well as on its current cloud deployment. The design turned
|
|
105
|
+
out to be genuinely content-independent — nothing in it assumes anything
|
|
106
|
+
bot-specific — so it's being extracted into its own project rather than
|
|
107
|
+
staying bot-only. `docs/design.md`'s own "Origin" section has the
|
|
108
|
+
originating project's actual settings inventory, kept for context on why
|
|
109
|
+
the design has the shape it has.
|
|
110
|
+
|
|
111
|
+
## The split that makes this portable
|
|
112
|
+
|
|
113
|
+
Two jobs, two owners, and only one of them is this library's job:
|
|
114
|
+
|
|
115
|
+
1. **Resolving a marked value to a plain value** — Trailsign's job, and
|
|
116
|
+
only Trailsign's job. Nothing here knows or cares what the resolved
|
|
117
|
+
value is *for*.
|
|
118
|
+
2. **Turning a resolved config block into a live object** — never
|
|
119
|
+
Trailsign's job. Each consumer owns its own small factory (a plain
|
|
120
|
+
name→constructor map) that builds whatever it needs from the
|
|
121
|
+
already-resolved values this library hands it.
|
|
122
|
+
|
|
123
|
+
Full reasoning for the split, plus two complete worked examples (a news
|
|
124
|
+
source's API key from an environment variable, a telemetry backend's
|
|
125
|
+
credential from a vault) with diagrams, is in `docs/design.md`.
|
|
126
|
+
|
|
127
|
+
## What's not decided yet
|
|
128
|
+
|
|
129
|
+
See `docs/design.md`'s own "Still open" section for full detail:
|
|
130
|
+
|
|
131
|
+
- A non-instance-principal auth shape for `oracleKeyVault` (today it only
|
|
132
|
+
works from inside an OCI compute instance)
|
|
133
|
+
- Validation-timing default (eager vs. lazy)
|
|
134
|
+
- A port to a second language
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Trailsign
|
|
2
|
+
|
|
3
|
+
A small, language-independent library for resolving application
|
|
4
|
+
settings from a declarative, self-describing config — where each value
|
|
5
|
+
states its own source (a literal, an environment variable, a vault
|
|
6
|
+
secret, ...) instead of the calling code assuming where to look.
|
|
7
|
+
|
|
8
|
+
```yaml
|
|
9
|
+
api-key:
|
|
10
|
+
trailsign-resolve: environment-variable
|
|
11
|
+
name: GNEWS_API_KEY
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`trailsign-resolve:` is a reserved, namespaced key — deliberately not a
|
|
15
|
+
bare word like `resolve` — so it can never collide with a consuming
|
|
16
|
+
project's own field names. It dispatches to a pluggable resolver;
|
|
17
|
+
whatever it resolves to is handed to the consumer as a plain value, with
|
|
18
|
+
no trace of where it came from left in the shape.
|
|
19
|
+
|
|
20
|
+
## Status
|
|
21
|
+
|
|
22
|
+
**Python package built out, as of 2026-09-01.** `src/trailsign/` is a
|
|
23
|
+
real installable package (`pyproject.toml`, src layout) with a test
|
|
24
|
+
suite covering the resolve walk, the three built-in resolvers
|
|
25
|
+
(`OracleKeyVaultResolver` verified against a real OCI Vault secret —
|
|
26
|
+
see `tools/verify_oracle_vault.py`), `validate()`'s combined-error
|
|
27
|
+
behavior, and the `trailsign-resolve` vs. `type` non-collision
|
|
28
|
+
regression. MIT licensed (see `LICENSE`). Public on GitHub; CI runs the
|
|
29
|
+
test suite on every push/PR. Not yet published to PyPI. A port to at
|
|
30
|
+
least one other language is still open, since the design's whole point
|
|
31
|
+
is being language-independent, not just Python.
|
|
32
|
+
|
|
33
|
+
### Installing it
|
|
34
|
+
|
|
35
|
+
Not on PyPI yet — until then, install straight from GitHub, ideally
|
|
36
|
+
pinned to a tag once one exists:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
pip install git+https://github.com/nankma/trailsign.git@main
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Install for development on this repo: `pip install -e ".[test]"`, then
|
|
43
|
+
`pytest`.
|
|
44
|
+
|
|
45
|
+
## Start here
|
|
46
|
+
|
|
47
|
+
- [`docs/design.md`](docs/design.md) — the core design: the config
|
|
48
|
+
shape, the resolve/dispatch contract (holds equally for a Go
|
|
49
|
+
`interface`, a Rust `trait`, or a Python `typing.Protocol`), why it's
|
|
50
|
+
shaped this way, two worked examples with diagrams, and what's still
|
|
51
|
+
undecided.
|
|
52
|
+
- [`src/trailsign/settings.py`](src/trailsign/settings.py) — the Python
|
|
53
|
+
reference implementation, matching `docs/design.md` exactly.
|
|
54
|
+
- [`tests/`](tests/) — the test suite; `tests/conftest.py` has a shared
|
|
55
|
+
fixture config mirroring `docs/design.md`'s worked examples.
|
|
56
|
+
- the `writing-system-design-docs` skill (global, not repo-local) — the
|
|
57
|
+
doc-writing convention `docs/design.md` follows, carried over
|
|
58
|
+
from where this project started in case future design docs here want
|
|
59
|
+
the same discipline (language-independent contracts, diagrams, a
|
|
60
|
+
"still open" section that's actually kept honest).
|
|
61
|
+
|
|
62
|
+
## Origin
|
|
63
|
+
|
|
64
|
+
This design started inside a Telegram news-trend bot (Auguring, formerly
|
|
65
|
+
Argus) while building a settings abstraction so that bot could run
|
|
66
|
+
standalone as well as on its current cloud deployment. The design turned
|
|
67
|
+
out to be genuinely content-independent — nothing in it assumes anything
|
|
68
|
+
bot-specific — so it's being extracted into its own project rather than
|
|
69
|
+
staying bot-only. `docs/design.md`'s own "Origin" section has the
|
|
70
|
+
originating project's actual settings inventory, kept for context on why
|
|
71
|
+
the design has the shape it has.
|
|
72
|
+
|
|
73
|
+
## The split that makes this portable
|
|
74
|
+
|
|
75
|
+
Two jobs, two owners, and only one of them is this library's job:
|
|
76
|
+
|
|
77
|
+
1. **Resolving a marked value to a plain value** — Trailsign's job, and
|
|
78
|
+
only Trailsign's job. Nothing here knows or cares what the resolved
|
|
79
|
+
value is *for*.
|
|
80
|
+
2. **Turning a resolved config block into a live object** — never
|
|
81
|
+
Trailsign's job. Each consumer owns its own small factory (a plain
|
|
82
|
+
name→constructor map) that builds whatever it needs from the
|
|
83
|
+
already-resolved values this library hands it.
|
|
84
|
+
|
|
85
|
+
Full reasoning for the split, plus two complete worked examples (a news
|
|
86
|
+
source's API key from an environment variable, a telemetry backend's
|
|
87
|
+
credential from a vault) with diagrams, is in `docs/design.md`.
|
|
88
|
+
|
|
89
|
+
## What's not decided yet
|
|
90
|
+
|
|
91
|
+
See `docs/design.md`'s own "Still open" section for full detail:
|
|
92
|
+
|
|
93
|
+
- A non-instance-principal auth shape for `oracleKeyVault` (today it only
|
|
94
|
+
works from inside an OCI compute instance)
|
|
95
|
+
- Validation-timing default (eager vs. lazy)
|
|
96
|
+
- A port to a second language
|