feat(workspace): state the linked workspace every turn, and mean the Altimate one

Merged
SA
2mo ago
+1337-193

Issue for this PR

Closes #1331

Follow-up to #1269 (closed by #1278): that fix named the workspace only inside the routing directive, so it still vanished whenever nothing was routed.

Type of change

  • Bug fix
  • New feature

What does this PR do?

Two related problems, one owner for the answer.

"Which workspace is this project linked to?" only had an answer when the workspace was routing something. #1278 rendered the binding from awareness.ts, whose contract is to stay silent unless there is a warehouse tool to steer. So an unlinked project, a link that could not be verified this turn, and a freshly created workspace with no integrations all rendered nothing — and the model filled the gap with whatever "workspace" was nearby in context.

"Workspace" means two unrelated things in the product — the Altimate Workspace a project is linked to, and Databricks' own "workspace" (plus IDE workspace folders). Nothing told the model which one an unqualified "workspace" meant, so it sometimes answered a Databricks question about the Altimate link, or vice versa, confidently.

The change:

  • New src/altimate/workspace/identity.ts renders a short ## Altimate Workspace section every turn from the binding itself (resolveBindingOutcome), independent of routing. Branches: bound (id, plus the name framed as an owner-chosen label; says an identity question resolves to this workspace and never another service's, in either direction), bound-but-stale ("last known … could not be re-verified just now" when the server could not be asked), unbound (says so, and how to link), unknown (asserts neither). Resolved at most once per 30 s per account+directory, single-flight, with a 1.5 s deadline after which the step renders last-known/unknown while the resolve continues. Behind the pilot flag like everything else.
  • Each branch scopes its instruction to a genuine identity question — "this/current/active workspace", or an unqualified "workspace" asking what this project is connected to. An earlier draft fired on any mention of the word and injected a linking pitch into unrelated Databricks conversations; identity.test.ts pins that the copy no longer does that, and that all three branches use the same trigger phrasing.
  • awareness.ts returns to routing only: bindingSection/NAMES_BINDING and the identity charge against its cap are removed, and nothing-materialised with no served extension tools is byte-identical silence again (with a live bridge serving extension tools it still renders the extension-only routing shape, as #1291 intended). The two #1291 tests that asserted the old line inside the routing output now assert silence. The reserved parameter #1278 added to assemble/routingSection is removed (it was always 0 once identity left this module). The routing intro names the workspace that serves the tools and never claims the link.
  • prompt.ts places the identity section right after the environment block, ahead of skills and the routing directive, since front-of-section content is treated as binding.
  • Two strings reworded so "workspace" means one thing: the Databricks auth prompt says <databricks-workspace-host>; the nothing-built validator says "this project is configured to require artifacts".

How did you verify your code works?

  • Rebased onto main at v0.12.0 (one conflict with #1291, a doc comment).
  • bun test over test/altimate/workspace, test/altimate/plugin, test/session/prompt*, test/altimate/validators: 1498 pass / 0 fail. New: identity.test.ts (17 cases: copy per branch, trigger scoping, hostile-name sanitising, cap boundary) and identity-section.test.ts (5 cases through Instance.provide: bound / unbound / unknown / pilot off / no instance context).
  • tsgo --noEmit clean.
  • Earlier in the cycle the bound and unbound copy was checked live against freemium from a main build: a plain session with no integrations answered "which workspace am I linked to?" with the workspace name and id first time.

Screenshots / recordings

N/A — system-prompt change; the rendered section for each branch is in identity.ts and pinned by the tests.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code

https://claude.ai/code/session_012Q51zFUmPg1WwtS5CrGJE6


Summary by cubic

States the linked Altimate Workspace to the model every turn, and makes "workspace" a single, unambiguous term in the product.

Previously the workspace binding was only stated inside the routing directive, which is silent whenever nothing is routed — so unlinked, unverifiable, or integration-less projects got no answer. A new identity.ts section (## Altimate Workspace) now renders unconditionally from the binding, with three branches: bound (names the workspace and id, and says identity questions resolve to it, never another service's "workspace"), unbound (says none is linked and how to link one), and unknown (asserts neither and says to retry). Each branch only fires on a genuine identity question, so the model no longer conflates the Altimate Workspace with Databricks' or an IDE's use of the word, and no longer injects a linking pitch into unrelated conversations.

  • awareness.ts reverts to routing only; nothing-materialised is byte-identical silence again, and the routing intro names the workspace that serves the tools, never the one the project is linked to.
  • The binding is resolved at most once per 30 seconds per project, re-checked instantly on a link change, and a step waits at most 1.5 s — a slow or unreachable server renders the last known binding ("last known to be linked… could not be re-verified") or "unknown" without stalling generation. The fallback's own reads are budgeted to 250 ms so the wait stays bounded even when they hang, and a resolve that threw is retried after 5 s instead of silencing identity for a full window. An outcome that lands after a link change or account switch is discarded, so it cannot overwrite the new state; the fallback reads under current credentials, so a mid-wait account switch cannot surface the other account's workspace.
  • The workspace label is budgeted on its encoded form so no name can clip the instruction; an id survives even when the name doesn't, and the section fails closed rather than truncating.
  • The section sits right after the environment block in prompt.ts, ahead of skills and routing.
  • Two strings are reworded so "workspace" means one thing: the Databricks auth prompt says <databricks-workspace-host> and the nothing-built validator says "this project is configured to require artifacts".

Summary by CodeRabbit

  • New Features

    • Added clearer Altimate Workspace identity information to assistant interactions, including linked, unlinked, stale, and temporarily unavailable states.
    • Workspace identity guidance now includes project-linking instructions.
    • Workspace references clarify when a workspace serves extension or warehouse tools.
    • Workspace names and IDs are displayed safely and consistently.
  • Bug Fixes

    • Clarified Databricks authorization instructions by identifying the workspace host.
    • Updated build-status guidance to refer to projects requiring artifacts.
    • Improved identity handling when links or account context change.
  • Tests

    • Added comprehensive coverage for identity behavior, caching, safety limits, and linking scenarios.