mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-16 04:33:16 +00:00
The `server.integrations.slack.default_channel` field was typed
`Option<InterpString>` but was never documented as interpolable — every
doc example uses a plain channel name like `#releases`. It resolved only
env vars, only once at server startup, and that capability was inherited
from a uniform schema-staging design, not a deliberate feature. This
brings it in line with every other server-scope config field, which were
already demoted to plain literals under the project rule that
interpolation belongs to fields resolved with run context.
## What changed
- **Type** (`fabro-types`, `fabro-config` layers):
`Option<InterpString>` → `Option<String>` in `SlackIntegrationSettings`
and `SlackIntegrationLayer`.
- **Demotion warning** (`resolve/server.rs`): calls
`warn_if_demoted_template` at resolve time with the field path
`server.integrations.slack.default_channel`, matching the pattern used
for earlier server-field demotions. A value still containing a `{{ env.*
}}`-shaped token is stored verbatim and triggers a startup warning — no
resolution, no error.
- **Startup wiring** (`server.rs`): the `value.resolve(process_env_var)`
call and its error mapping are deleted; the literal string is passed
directly to `SlackService::new`, which already accepts `Option<String>`.
- **System status handler** (`handler/system.rs`): removed the
now-unnecessary `display_interp` helper that called `resolve_or_source`;
the field is cloned directly into the metadata map.
- **Wire shape**: unchanged. `InterpString` serialized as its raw source
string, so stored/wire JSON is identical before and after. The OpenAPI
spec is untouched.
## What is not changing
Per-run Slack channels — `run.notifications.<route>.slack.channel` and
`run.interviews.slack.channel` — remain `InterpString` with variable
substitution at run creation. Those are the intended interpolating
surface and are correct as-is.
## Migration signal
Anyone who placed a `{{ env.NAME }}` token in
`server.integrations.slack.default_channel` (only possible during ~3
months of nightly builds) will see a startup warning naming the field.
The value is treated as a literal; no data is lost and startup does not
fail.
## Interview-prompt routing observation (step 4)
The interview-prompt posting path checks `run.interviews.slack.channel`
first and falls back to the server default only when the run-scope field
is absent — the preference already exists. No routing change is needed
or made here.
### Fabro Details
<details>
<summary>Ran 8 stages in 41m 23s for $10.10</summary>
| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 1s | – | 0 |
| preflight_compile | 2m 41s | – | 0 |
| preflight_lint | 2m 42s | – | 0 |
| implement | 0s | – | 0 |
| simplify_fable | 27m 43s | $10.10 | 0 |
| simplify_gpt | 0s | – | 0 |
| verify | 7m 44s | – | 0 |
| **Total** | **41m 23s** | **$10.10** | **0** |
</details>
<details>
<summary>Ran <code>ImplementPlan.fabro</code> (11 nodes and 14
edges)</summary>
```dot
digraph ImplementPlan {
graph [
goal="Implement and simplify",
model_stylesheet="
* { model: claude-opus-4-8; }
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo +nightly-2026-04-14 clippy -q --workspace --all-targets -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD. Be sure to use the rust-style-guide skill to help you follow this repo's Rust style conventions.", model="gpt-55", reasoning_effort="xhigh"]
simplify_fable [label="Simplify (Fable)", prompt="@prompts/simplify.md", model="claude-fable-5", reasoning_effort="xhigh"]
simplify_gpt [label="Simplify (GPT-55)", prompt="@prompts/simplify.md", model="gpt-55"]
verify [label="Verify", shape=parallelogram, timeout="1800s", script="git fetch origin main 2>&1 && git merge --no-edit --no-stat origin/main 2>&1 && cargo +nightly-2026-04-14 fmt --all 2>&1 && cargo dev docs refresh 2>&1 && cargo +nightly-2026-04-14 fmt --check --all 2>&1 && { command -v rg >/dev/null 2>&1 || { echo 'rg is required for verify'; exit 127; }; } && ! rg -n 'AuthMode::Disabled|RunAuthMethod|RunSubjectProvenance|\bActorRef\b|\bActorKind\b|AuthenticatedSubject|AuthenticatedService|AuthorizeRunScoped|AuthorizeRunBlob|AuthorizeStageArtifact|AuthorizeCommandLog|auth_method\s*==\s*\"disabled\"' lib/crates apps lib/packages docs/public/api-reference/fabro-api.yaml 2>&1 && cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings 2>&1 && cargo nextest run --workspace --status-level slow --profile ci 2>&1 && cargo dev docs check 2>&1 && bun install --frozen-lockfile 2>&1 && (cd apps/fabro-web && bun run typecheck) 2>&1 && (cd apps/fabro-web && bun run test) 2>&1 && (cd lib/packages/fabro-api-client && bun run typecheck) 2>&1 && cargo dev build -- -p fabro-cli --release 2>&1", goal_gate=true, retry_target="fixup"]
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all format, clippy, Rust test, docs, TypeScript typecheck/test, and build failures.", max_visits=3]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=succeeded"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=succeeded"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=succeeded"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_fable -> simplify_gpt -> verify
verify -> exit [condition="outcome=succeeded"]
verify -> fixup
fixup -> verify
}
```
</details>
⚒️ Generated with [Fabro](https://fabro.sh)
---------
Co-authored-by: Fabro <noreply@fabro.sh>
|
||
|---|---|---|
| .. | ||
| build-support | ||
| fabro-acp | ||
| fabro-agent | ||
| fabro-api | ||
| fabro-auth | ||
| fabro-automation | ||
| fabro-checkpoint | ||
| fabro-cli | ||
| fabro-client | ||
| fabro-config | ||
| fabro-core | ||
| fabro-db | ||
| fabro-dev | ||
| fabro-dump | ||
| fabro-environment | ||
| fabro-github | ||
| fabro-graphviz | ||
| fabro-hooks | ||
| fabro-http | ||
| fabro-install | ||
| fabro-interview | ||
| fabro-llm | ||
| fabro-macros | ||
| fabro-manifest | ||
| fabro-mcp | ||
| fabro-mcp-server | ||
| fabro-mcp-store | ||
| fabro-model | ||
| fabro-oauth | ||
| fabro-options-metadata | ||
| fabro-proc | ||
| fabro-redact | ||
| fabro-sandbox | ||
| fabro-server | ||
| fabro-slack | ||
| fabro-spa | ||
| fabro-static | ||
| fabro-store | ||
| fabro-telemetry | ||
| fabro-template | ||
| fabro-test | ||
| fabro-tool | ||
| fabro-tracker | ||
| fabro-types | ||
| fabro-util | ||
| fabro-validate | ||
| fabro-variable | ||
| fabro-vault | ||
| fabro-workflow | ||