feat: add versioned execution profiles
This commit is contained in:
parent
641e85f5a8
commit
1cd890d871
34 changed files with 2087 additions and 471 deletions
|
|
@ -1,76 +1,34 @@
|
|||
# Channel contract
|
||||
|
||||
How an external invocation reaches the gateway, per `GLAS-WP-0003`.
|
||||
Mirrors `docs/harness-contract.md`'s `Rein` at a different layer: `Rein`
|
||||
governs how a session runs once glas-harness has decided to run one; a
|
||||
`Channel` governs how an external caller (CLI today; a future Slack
|
||||
message, HTTP request, or scheduled trigger) gets translated into that
|
||||
decision in the first place, and how the result gets translated back.
|
||||
|
||||
## Interface
|
||||
A channel translates an external invocation into profile-driven gateway input;
|
||||
it does not select a rein class or execute a provider itself.
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class GatewayInvocation:
|
||||
"""Everything run_task_through_rein needs, channel-agnostic."""
|
||||
sandbox_profile: str
|
||||
harness_profile: str
|
||||
repo: str
|
||||
title: str
|
||||
description: str
|
||||
actor: str = "agt"
|
||||
project: str = "glas-harness"
|
||||
report_to_hub: bool = True
|
||||
|
||||
|
||||
class Channel(ABC):
|
||||
"""Base class for concrete invocation channels (CLI, Slack, HTTP, ...)."""
|
||||
|
||||
@abstractmethod
|
||||
def parse_invocation(self, raw: Any) -> GatewayInvocation:
|
||||
"""Turn a channel-specific invocation into a GatewayInvocation."""
|
||||
|
||||
@abstractmethod
|
||||
def render_result(self, result: dict[str, Any]) -> Any:
|
||||
"""Turn a gateway result dict into whatever this channel returns."""
|
||||
```
|
||||
|
||||
`src/glas_harness/channels/base.py`. A channel does not choose the rein
|
||||
or run the gateway itself — `cli.py`'s `main()` still does that, calling
|
||||
`parse_invocation`/`render_result` around the existing
|
||||
`run_task_through_rein` call. Keeping channel construction and gateway
|
||||
invocation separate (rather than folding gateway-calling into the
|
||||
`Channel` ABC itself) is what lets `CLIChannel` be a pure
|
||||
input/output mapper, easy to unit test without touching sand-boxer or a
|
||||
rein at all.
|
||||
`CLIChannel` is the current implementation. The CLI requires
|
||||
`--harness-profile <id[@version]>`; the old sandbox-only input is removed
|
||||
because it could not identify the rein, model route, tool policy, or contract
|
||||
revision. Channels may obtain a profile choice from their own approved
|
||||
configuration, but must pass it explicitly and must surface resolution refusal
|
||||
to their caller.
|
||||
|
||||
## CLIChannel — the first, and so far only, implementation
|
||||
The channel renders the full direct `GatewayResult`. State Hub receives only
|
||||
the compact `ExecutionEvidence` subset.
|
||||
|
||||
`src/glas_harness/channels/cli_channel.py`. Maps an argparse
|
||||
`Namespace` to `GatewayInvocation` (one field each, `--no-hub` inverts
|
||||
to `report_to_hub`) and renders a result dict as
|
||||
`json.dumps(result, indent=2)` — exactly what `cli.py` did inline before
|
||||
this existed. This was a refactor, not a behavior change: verified with
|
||||
a real live run through `python3 -m glas_harness.cli run ...` producing
|
||||
byte-identical output shape to the pre-refactor version, plus unit tests
|
||||
for the mapping in isolation (`tests/test_cli_channel.py`).
|
||||
## Adding a channel
|
||||
|
||||
## Adding a second channel (not done — pattern only)
|
||||
|
||||
No second channel exists yet, and none should be built speculatively —
|
||||
same discipline as ADR-002/ADR-004 (generalize from a real second
|
||||
example, not in anticipation of one). If/when one is needed, e.g. a
|
||||
Slack channel:
|
||||
|
||||
1. Implement `Channel` in `src/glas_harness/channels/slack_channel.py`:
|
||||
`parse_invocation` turns a Slack event payload into a
|
||||
`GatewayInvocation` (message text → `title`/`description`, a
|
||||
configured default `sandbox_profile`, the Slack user id as `actor`
|
||||
or `project`); `render_result` turns the result dict into a Slack
|
||||
message (success/failure, commit sha if present).
|
||||
2. Whatever process receives Slack events constructs the channel and
|
||||
calls `run_task_through_rein` the same way `cli.py` does — no change
|
||||
needed to `gateway.py`, `contract.py`, or any rein.
|
||||
3. If two real channels turn out to share invocation-parsing logic (e.g.
|
||||
both need the same `sandbox_profile` defaulting rule), factor that
|
||||
shared piece out then — not before, and not into the `Channel` ABC
|
||||
itself unless every channel needs it.
|
||||
Implement `parse_invocation` and `render_result`, then call `run_execution`
|
||||
with an `ExecutionRequest`. Carry any assignment/role/duty/goal/resource
|
||||
references supplied by the upstream workforce system. Do not duplicate profile
|
||||
resolution, sandbox coordination, leadership decisions, or rein construction in
|
||||
the channel.
|
||||
|
|
|
|||
62
docs/evidence/GLAS-WP-0004-live-proof-2026-08-20.md
Normal file
62
docs/evidence/GLAS-WP-0004-live-proof-2026-08-20.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# GLAS-WP-0004 live profile evidence — 2026-08-20
|
||||
|
||||
Acceptance task for both profiles: change one `README.md` status value from
|
||||
`pending` to `complete`, make no other content change, and commit it. Each run
|
||||
used a separate temporary initialized repository and `profile.bwrap-local`.
|
||||
No credential value, prompt transcript, or raw model output is recorded here.
|
||||
|
||||
## `harness.agent-dev-local@1.0.0`
|
||||
|
||||
- Result: succeeded.
|
||||
- Contract: `1.0`.
|
||||
- Rein: `rein-aharness@0.1.0`.
|
||||
- Model route/resolved model: `claude-code-cli` / `claude-sonnet-4-6`.
|
||||
- Tool profile: `green-commit-only`.
|
||||
- Sandbox ID: `e61624cb`; local lifecycle store verified `destroyed`.
|
||||
- Request ID: `96b2ec85-3823-4088-bcf4-a008c02e2354`.
|
||||
- Commit: `795f8ef8b414f4470e812005f4103b8c5f126829`.
|
||||
- Tool-event visibility: complete, 14 events.
|
||||
- Reported execution time: 29.051 seconds.
|
||||
|
||||
The first attempt also proved normalized dependency/startup failure and
|
||||
sandbox cleanup: the acceptance environment lacked rein-aharness's optional
|
||||
`llm-connect` install. After installing the documented sibling dependency, the
|
||||
same profile and task succeeded. Production packaging must install the concrete
|
||||
rein with its execution dependencies.
|
||||
|
||||
## `harness.agent-dev-openweights-local@1.0.0`
|
||||
|
||||
- Result: succeeded on the 2026-08-21 local-time recheck after credential repair.
|
||||
- Contract: `1.0`.
|
||||
- Rein: `rein-openweights@0.1.0`.
|
||||
- Model route/resolved model: `rein-openweights-openrouter` /
|
||||
`qwen/qwen-2.5-72b-instruct`.
|
||||
- Tool profile: `green-commit-only`.
|
||||
- Sandbox ID: `220482bc`; local lifecycle store verified `destroyed`.
|
||||
- Request ID: `b783af7f-e728-4dee-9034-f1c2262aa9ea`.
|
||||
- Commit: `b0600b25066731c6e1fc458409429f76a844f959`.
|
||||
- Turns/tokens: 3 / 3,497 of the 60,000-token profile budget.
|
||||
- Tool-event visibility: unavailable, reported explicitly rather than as an
|
||||
empty claim of completeness.
|
||||
- Reported execution time: 300.095 seconds.
|
||||
|
||||
The recheck exposed two credential-selection facts without revealing a value:
|
||||
an inherited `OPENROUTER_API_KEY` still contained the retired key and therefore
|
||||
masked the repaired workload lane, while the AppRole files existed at the
|
||||
documented standard directory but code required an environment variable to use
|
||||
them. The successful run removed the stale ambient override and selected the
|
||||
approved AppRole directory. `rein-openweights` now defaults to
|
||||
`~/.local/rein-openweights/approle`; explicit environment credentials retain
|
||||
development precedence and are documented as needing refresh/removal after
|
||||
rotation.
|
||||
|
||||
## Acceptance status
|
||||
|
||||
Both explicit profiles resolved and dispatched distinct rein/model
|
||||
constellations, completed the same semantic task with a real commit, returned
|
||||
the common Glas evidence envelope, and destroyed their local sandboxes. No
|
||||
alternative workload credential was borrowed.
|
||||
|
||||
Rollback for consumers is to repin to the last approved Glas profile. The old
|
||||
`--sandbox-profile` governed path and implicit `ReinAharness()` default are not
|
||||
restored.
|
||||
87
docs/execution-profiles.md
Normal file
87
docs/execution-profiles.md
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
# Execution profiles and workforce handoff
|
||||
|
||||
Glas profiles are versioned execution constellations. They make the execution
|
||||
layer replaceable without changing an upstream workforce assignment.
|
||||
|
||||
```text
|
||||
RoleAssignment / activity / channel
|
||||
| organizational refs + bounded task + harness_profile_ref
|
||||
v
|
||||
ExecutionRequest
|
||||
| deterministic profile validation
|
||||
v
|
||||
rein + model route + sandbox profile + tool profile + limits
|
||||
| one outer lifecycle
|
||||
v
|
||||
ExecutionEvidence -> assignment/audit consumers
|
||||
```
|
||||
|
||||
## Profile schema
|
||||
|
||||
Each YAML document under `profiles/` declares:
|
||||
|
||||
- stable `id`, semantic `version`, exact `contract_version`, and status;
|
||||
- rein registry ID and required capabilities;
|
||||
- sand-boxer `sandbox_profile`;
|
||||
- rein-enforced `tool_profile`;
|
||||
- model provider, explicit model identifier, model class, and route;
|
||||
- positive token/timeout/turn limits when applicable; and
|
||||
- credential route references and non-secret metadata.
|
||||
|
||||
The catalog discovers files deterministically, forbids unknown schema fields,
|
||||
rejects duplicate revisions, and checks the selected profile against
|
||||
`registry/reins/*.yaml`. Unpinned lookup is accepted only when exactly one
|
||||
enabled revision exists. Inline secrets and token-looking values are refused.
|
||||
|
||||
Use `glas-harness profiles` as the catalog/packaging validation command.
|
||||
|
||||
Catalog validation proves schema/compatibility, not host installation. An
|
||||
execution host must install `glas-harness` with sand-boxer support and each rein
|
||||
used by its enabled profiles. The Claude-backed rein also needs its documented
|
||||
`rein-aharness[llm]`/sibling `llm-connect` adapter dependency. Missing runtime
|
||||
dependencies surface as startup/execution failure evidence and still trigger
|
||||
sandbox teardown.
|
||||
|
||||
## Consumer request
|
||||
|
||||
See `examples/execution-request.json`. Consumers know only a profile reference,
|
||||
not `ReinAharness`, `ReinOpenWeights`, Claude Code arguments, or OpenRouter
|
||||
client details. An assignment system may set the organizational references; a
|
||||
channel may omit fields it does not own.
|
||||
|
||||
If the requested profile, contract, rein, capability, resource envelope, or
|
||||
credential route is unavailable, the caller must receive a refusal/failure. No
|
||||
consumer may silently substitute a different rein or model constellation.
|
||||
|
||||
The current exact-profile path does not interpret resource envelopes or choose
|
||||
profiles from requirements. A future requirements resolver belongs at this
|
||||
Glas boundary, must be deterministic and explainable, and must refuse ambiguity.
|
||||
|
||||
## Two equivalent selections
|
||||
|
||||
For the same task and organizational references, switch only:
|
||||
|
||||
```text
|
||||
harness.agent-dev-local@1.0.0
|
||||
-> rein-aharness / claude-sonnet-4-6 / profile.bwrap-local
|
||||
|
||||
harness.agent-dev-openweights-local@1.0.0
|
||||
-> rein-openweights / qwen/qwen-2.5-72b-instruct / profile.bwrap-local
|
||||
```
|
||||
|
||||
Both use `green-commit-only` and return `GatewayResult` / `ExecutionEvidence`.
|
||||
This proves interchangeability at the Glas boundary; it does not claim the
|
||||
models have identical quality, price, or provider behavior.
|
||||
|
||||
## Ownership handoff
|
||||
|
||||
- Agentic-resources/KaizenAgentic: leadership, role, duty, goal, resource
|
||||
envelope, worker/agent instance, and assignment definitions.
|
||||
- Activity-core or a channel: when work is invoked and the bounded task input.
|
||||
- Glas: versioned execution selection, lifecycle, attribution, and evidence.
|
||||
- Rein: inner loop, backend-specific policy enforcement and credentials.
|
||||
- llm-connect/provider: inference/provider boundary and model capabilities.
|
||||
- Sand-boxer: sandbox profiles, placement, provisioning, and teardown.
|
||||
|
||||
Rollback is selection-based: repin a caller to its last approved Glas profile.
|
||||
Do not bypass Glas with `--sandbox-profile` or add a hidden default rein.
|
||||
|
|
@ -1,124 +1,97 @@
|
|||
# Harness contract
|
||||
|
||||
The interface a concrete harness backend ("rein") implements so glas-harness
|
||||
can route to it, per `docs/adr/ADR-001-rein-harness-family.md`. Mirrors
|
||||
sand-boxer's `SandboxExtension` ABC (`provision`/`wait_ready`/`teardown`) at
|
||||
the harness level, one layer up: sand-boxer establishes *where* dangerous
|
||||
work runs, this contract governs *how an agent session runs* on top of it.
|
||||
Contract version: `1.0` (`glas_harness.contract.CONTRACT_VERSION`).
|
||||
|
||||
## Interface
|
||||
This is the stable boundary between Glas, its consumers, and concrete harness
|
||||
backends (reins). Glas owns profile resolution and the outer lifecycle; a rein
|
||||
owns its inner agentic loop. Sand-boxer owns environment provisioning.
|
||||
|
||||
## Consumer boundary
|
||||
|
||||
`ExecutionRequest` requires an explicit `harness_profile_ref`, repository,
|
||||
title, and description. It may carry correlation and organizational references
|
||||
(`assignment_ref`, `role_ref`, `duty_ref`, `goal_refs`, and
|
||||
`resource_envelope_refs`). Those references link execution evidence to
|
||||
leadership/workforce records; they do not transfer organizational authority to
|
||||
Glas.
|
||||
|
||||
The gateway returns `GatewayResult` with:
|
||||
|
||||
- `ok`, derived from normalized outcome;
|
||||
- `evidence`, safe for compact State Hub reporting; and
|
||||
- direct-caller-only `tool_output` and `tool_error`.
|
||||
|
||||
Raw prompts, model output, tool output, and credential material are excluded
|
||||
from the State Hub detail.
|
||||
|
||||
## Rein lifecycle
|
||||
|
||||
```python
|
||||
class Rein(ABC):
|
||||
"""Base class for concrete harness backends (reins)."""
|
||||
|
||||
@abstractmethod
|
||||
def start_session(
|
||||
self, profile: HarnessProfile, inputs: dict[str, str], sandbox: SandboxHandle
|
||||
) -> dict[str, str]:
|
||||
"""Begin an agent session bound to a sandbox. Returns a session handle."""
|
||||
) -> dict[str, str]: ...
|
||||
|
||||
@abstractmethod
|
||||
def dispatch_tool(
|
||||
self, session: dict[str, str], tool_call: ToolCall
|
||||
) -> ToolResult:
|
||||
"""Run one tool call under the session's policy. Returns result + audit envelope."""
|
||||
) -> ToolResult: ...
|
||||
|
||||
@abstractmethod
|
||||
def end_session(self, session: dict[str, str]) -> dict[str, str]:
|
||||
"""Close the session. Returns a summary (commit sha, tokens, duration, outcome)."""
|
||||
def end_session(self, session: dict[str, str]) -> ExecutionSummary: ...
|
||||
```
|
||||
|
||||
- `start_session` resolves the rein's own setup (persona/blueprint loading,
|
||||
credential acquisition) against the sandbox handle glas-harness already
|
||||
obtained from sand-boxer — the rein never provisions or tears down a
|
||||
sandbox itself.
|
||||
- `dispatch_tool` enforces the tool-profile allow-list glas-harness resolved
|
||||
(the same allow-list concept rein-aharness's `profiles.py` already
|
||||
implements today, just invoked through the contract instead of only the
|
||||
rein's own CLI).
|
||||
- `end_session` is where the existing "commit exists = success" signal
|
||||
(rein-aharness) or an equivalent per-rein success criterion is reported
|
||||
back to glas-harness for State Hub posting. glas-harness posts the audit
|
||||
event; the rein returns the facts.
|
||||
|
||||
## Session lifecycle (who calls what)
|
||||
|
||||
```
|
||||
glas-harness rein sand-boxer
|
||||
──────────── ──── ──────────
|
||||
resolve harness.* profile
|
||||
request sandbox ──────────────────────────────▶ create()
|
||||
receive sandbox handle ◀──────────────────────────────
|
||||
start_session(profile, in, sbx) ─▶ acquire creds, load persona
|
||||
◀─ session handle
|
||||
dispatch_tool(session, call) ─▶ run under allow-list
|
||||
◀─ result + audit envelope
|
||||
(repeat dispatch_tool ...)
|
||||
end_session(session) ─▶ verify success, summarize
|
||||
◀─ summary
|
||||
post State Hub event
|
||||
request sandbox teardown ──────────────────────────────▶ destroy()
|
||||
```text
|
||||
Glas rein sand-boxer
|
||||
---- ---- ----------
|
||||
resolve profile + rein descriptor
|
||||
create sandbox ------------------------------------------> create
|
||||
start_session(profile, inputs, handle) -> rein setup
|
||||
dispatch_tool(session, call) -> inner loop
|
||||
end_session(session) -> normalized facts
|
||||
destroy sandbox -----------------------------------------> destroy
|
||||
publish compact ExecutionEvidence
|
||||
```
|
||||
|
||||
glas-harness owns the *outer* loop (profile resolution, sandbox
|
||||
request/teardown, State Hub reporting, actor attribution). The rein owns
|
||||
the *inner* loop (its own agentic reasoning, whatever that looks like —
|
||||
Claude Code CLI subprocess for `rein-aharness`, a direct OpenRouter
|
||||
tool-use loop for `rein-openweights`).
|
||||
There is no production default rein. Direct `Rein` injection remains a narrow
|
||||
library/test seam but still requires a valid profile so profile, sandbox,
|
||||
model, tool policy, and evidence are explicit.
|
||||
|
||||
## Actor attribution
|
||||
## Stability and extension rules
|
||||
|
||||
Every `dispatch_tool` call and lifecycle transition carries an actor
|
||||
(`adm`/`agt`/`atm`) per glas-harness INTENT.md's audit requirement.
|
||||
glas-harness stamps this at dispatch time; reins do not need their own
|
||||
actor model.
|
||||
All contract models use Pydantic with unknown fields forbidden. Stable `1.0`
|
||||
fields are the declared fields in `src/glas_harness/contract.py`. Optional
|
||||
measurements such as tokens, duration, resolved model, commit, and artifacts
|
||||
remain `null` when unknown; unsupported tool-event visibility is
|
||||
`unavailable`, not an empty claim of completeness.
|
||||
|
||||
## Composable reins as middleware (deferred — sketch only, no code)
|
||||
Rein-specific, non-secret additions belong only in declared `metadata` fields.
|
||||
Adding a required field, changing a field meaning/type, or removing a field
|
||||
requires a new contract version. Adding an optional field may remain compatible
|
||||
only when old consumers can safely ignore it and every strict boundary model is
|
||||
updated together. A profile and rein descriptor must both declare the exact
|
||||
supported contract version.
|
||||
|
||||
`docs/adr/ADR-002-credential-brokering-and-composable-reins.md` part 2
|
||||
raised whether monitoring/evaluation/optimization should become their
|
||||
own composable reins — middleware that wraps or observes a base rein's
|
||||
`dispatch_tool` calls, rather than each being a complete alternative
|
||||
harness backend the way `rein-aharness`/`rein-openweights` are. Resolved
|
||||
in `docs/adr/ADR-004-composable-reins-stay-deferred.md`: **still
|
||||
deferred, sketch recorded, no code written.** The two observability
|
||||
additions since (rein-aharness's per-tool-call audit stream,
|
||||
`glas-harness`'s own gateway hub event) both turned out to be simpler as
|
||||
direct implementations — neither needed a separate wrapping rein — so
|
||||
there still isn't a second real capability wanting this shape, only the
|
||||
original one (llm-connect's optional Functional-layer modules,
|
||||
untouched).
|
||||
Sensitive values are never contract extensions. Profiles may contain
|
||||
credential-route references, while credential resolution and provider setup
|
||||
remain rein-local under ADR-002.
|
||||
|
||||
If a real second candidate appears, the shape would be:
|
||||
## Failure semantics
|
||||
|
||||
```python
|
||||
class Middleware(ABC):
|
||||
"""Wraps another Rein's dispatch_tool, does not replace start_session/end_session."""
|
||||
The gateway returns evidence for every normal refusal/failure path:
|
||||
|
||||
def __init__(self, inner: Rein) -> None:
|
||||
self.inner = inner
|
||||
- `resolution`: unknown, disabled, ambiguous, incompatible, or unsafe profile;
|
||||
- `sandbox_create`;
|
||||
- `session_start`;
|
||||
- `execution` (including a rein-declared unsuccessful result);
|
||||
- `session_end`; and
|
||||
- `teardown`.
|
||||
|
||||
@abstractmethod
|
||||
def dispatch_tool(self, session: dict[str, str], tool_call: ToolCall) -> ToolResult:
|
||||
"""Call self.inner.dispatch_tool(...), observe/transform, return the result."""
|
||||
Profile resolution happens before sandbox creation. Once a sandbox exists,
|
||||
teardown is attempted on every path. `refused` means governed execution did not
|
||||
proceed; `failed` means an attempted lifecycle did not complete successfully.
|
||||
|
||||
def start_session(self, profile, inputs, sandbox) -> dict[str, str]:
|
||||
return self.inner.start_session(profile, inputs, sandbox)
|
||||
## Deliberate non-goals
|
||||
|
||||
def end_session(self, session) -> dict[str, str]:
|
||||
return self.inner.end_session(session)
|
||||
```
|
||||
|
||||
A chain of `Middleware` wrapping a base `Rein` still satisfies the `Rein`
|
||||
ABC itself (composition, not a parallel type), so glas-harness's gateway
|
||||
would not need to change to consume one — this is deliberately *not* a
|
||||
speculative gateway-side change, just a documented shape to reach for
|
||||
if/when a second candidate shows up.
|
||||
|
||||
## Open questions this contract does not resolve yet
|
||||
|
||||
- The exact `SandboxHandle`/`ToolCall`/`ToolResult` field shapes — these
|
||||
have stabilized in practice (both reins implement them identically)
|
||||
but are not yet declared frozen/versioned the way sand-boxer's models
|
||||
are.
|
||||
The contract does not schedule work, source blueprints, allocate workers,
|
||||
resolve leadership, broker credentials, select an unapproved model by price, or
|
||||
standardize rein internals. Composable rein middleware remains deferred by
|
||||
ADR-004 until a second concrete need exists.
|
||||
|
|
|
|||
38
docs/intakes/residuals.md
Normal file
38
docs/intakes/residuals.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# glas-harness residual intakes
|
||||
|
||||
## GLAS-IN-0001 — Restore open-weight live-profile credential lane
|
||||
|
||||
```yaml
|
||||
id: GLAS-IN-0001
|
||||
kind: intake
|
||||
title: "Restore the rein-openweights OpenRouter lane and close the dual-profile live proof"
|
||||
lane: blue
|
||||
status: done
|
||||
priority: high
|
||||
owner: ops-mason
|
||||
repo: glas-harness
|
||||
origin: residual
|
||||
origin_ref: GLAS-WP-0004
|
||||
description: |
|
||||
On 2026-08-20, harness.agent-dev-openweights-local@1.0.0 resolved and
|
||||
dispatched the same bounded fixture used by the successful rein-aharness
|
||||
profile. The existing rein-local credential reached OpenRouter but the
|
||||
provider returned HTTP 401 User not found before a model turn. Glas returned
|
||||
normalized, redacted failure evidence and tore down sandbox bc9dec6a.
|
||||
|
||||
Route catalog id: rein-openweights-openrouter-approle. Credential values must
|
||||
not be placed in this record, State Hub, Git, or chat.
|
||||
|
||||
The owning credential operator should rotate or repair that exact workload
|
||||
lane, verify field presence without disclosure, and notify glas-harness.
|
||||
Then rerun the bounded acceptance task through
|
||||
harness.agent-dev-openweights-local@1.0.0, record a real commit plus cleanup
|
||||
evidence, and mark GLAS-WP-0004-T07 done. Do not borrow llm-connect's
|
||||
separate OpenRouter credential.
|
||||
|
||||
Completed 2026-08-21. The repaired lane authenticated after removing a stale
|
||||
inherited OPENROUTER_API_KEY override and selecting the standard AppRole
|
||||
directory. The profile completed in 3 turns, spent 3,497 tokens, produced
|
||||
commit b0600b25066731c6e1fc458409429f76a844f959, and sandbox 220482bc was
|
||||
verified destroyed. The AppRole directory is now the code default.
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue