Skip to content

Command Center: a walking skeleton that loads the Truss provider - #13

Open
unional wants to merge 21 commits into
mainfrom
github-6/command-center-walking-skeleton
Open

Command Center: a walking skeleton that loads the Truss provider#13
unional wants to merge 21 commits into
mainfrom
github-6/command-center-walking-skeleton

Conversation

@unional

@unional unional commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Opens the Command Center work for #6 and lands the first runnable slice.

Two things happen here. The extension contract is specified and judged, and a walking skeleton is built against it — deliberately in that order, and deliberately stopping short of a freeze.

Why it is not frozen

The contract reached 26 scenarios across three cold review passes with zero lines of implementation behind it. Nothing had tested whether it survives a real process, and freezing a contract before one has met it is the expensive mistake. So the slice was built first, and it corrected the contract twice:

  • An artifact-set with no members had to be a first-class outcome rather than an error. Declaring a set is an act of intent, so it may start empty and be discharged later — that is how a repository adopts a standard it does not yet meet. Emptiness is an obligation on the set, never a strain on a connection.
  • A view that only renders under a TTY cannot be tested, so a non-TTY single-render path exists.

Exercised: discovery, load, the handshake, per-contract version refusal and partial bind, refusing a contract a binding does not carry, snapshot freshness including stale-never-live, unload.
Not exercised, and therefore not frozen: actions, references, the no-replay path.

What runs

node packages/command-center/dist/cli.js

Three views — artifact-sets with what must hold between them, open obligations, and a force-directed graph of the lattice in the terminal. Verified running in a herdr pane opened with cyber-mux open, driven remotely to confirm each view and refresh.

The host understands none of what it renders: a snapshot is an opaque payload carrying its provenance and freshness, which is the claim the segregated contract makes.

The Truss provider

Reads two real files and invents nothing: .truss/lattice.toml (also added here — what this repo declares it should hold) and docs/backlog.md, which the lattice model already calls a hand-maintained obligation ledger. One field is simulated and flagged proposal: true: a connection's evaluation status, because held | strained | unevaluated is a backlog item rather than settled model.

Running it against this repo immediately surfaced a real conformance strain, filed as #12: AGENTS.md documents a docs/adr/ directory that does not exist, and the backlog cites an ADR inside it. Nothing checks that relation, so it does not score as unstrained — it scores as never checked, which is the case for the application existing.

Also here

Review notes

  • Written implementation-first, against this repo's TDD rule. Tests came after and cover the branches the spec names; the order was wrong and the commit says so.
  • pnpm verify green: lint, build, typecheck, 39 tests, knip.
  • The package is private, so no changeset is owed.

Refs #6

unional and others added 17 commits September 7, 2026 21:31
No SDD corpus existed in this repo, so kicking off cyber-truss#6 starts on
the backfill path: scaffold the project spec before the change request can
be explored.

One package, `packages/command-center`, with the contract reached through a
subpath export — providers in cyberplace and cyber-sdd bind to the contract,
and a separate contract package stays reversible until the first external
provider ships.

Spec is colocated (an npm package excludes `.agents/` from its tarball),
capability-first, in intent mode: the project has no source yet, so the
capabilities come from the initiative rather than from a tree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
The contract is segregated rather than monolithic: every provider implements a
small handshake and then declares which of four capability contracts —
references, state, views, actions — it implements. Each carries its own version,
so refusing an incompatible `actions` contract does not refuse a provider that
only ever reported state.

Providers are out-of-process. That is what makes the issue's restart criterion
testable: the host holds snapshots it never promotes on its own, and an action
whose outcome is unknown is never sent a second time.

19 scenarios across five use-case groups. check-suite, check-spec-state and
check-spec-structure are clean. Not yet frozen — the spec gate has not run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
…sions

Self-alignment against the three lens bars, loaded after the spec-judge blocked
on a governance pre-flight.

The Oracle bar grades the actor enumeration both ways, and the integration
author was listed as an actor while carrying no use case. They implement the
provider; they never call the host. Reclassified as a stakeholder, which also
gives the per-contract version refusal the stakeholder it protects.

The Architect and Builder bars both require every stated extension to be a path
in the drawn graph. Unloading during an action was claimed as a dispatchAction
divergence while its path lives in the unload sub-graph — moved to the entry
point that reaches it.

Concept tag restated the folder it sits in, so it carried no cross-cutting
information; it is lifecycle and provenance.

Scenario map named one edge two ways, hiding permutation coverage as two edges.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
The judge cleared pre-flight and returned CHANGE with six findings. It also
confirmed the load-bearing question: per-contract refusal is not the rejected
capability-negotiation scheme wearing a new name, because the host omits an
incompatible contract rather than adapting to it.

refreshState guarded nothing while dispatchAction guarded the identical
question, so calling it for a contract the binding does not carry was
undefined — which is exactly where the partial-bind path had to be specified.

The references contract was declared and never specified, and the issue's
fourth acceptance bullet needs it: a fleet completion, an SDD gate result and
a Truss obligation are only distinguishable if a reference can be followed
into the domain that owns it. It now has a use case, a graph and four
scenarios, and the provenance scenario carries all three domains rather than
two.

The views contract is cut. Nothing needed it, and whether renderable views are
a distinct area from state is a question the TUI answers; declaring it now was
a commitment made before it had to be.

Two scenarios described their trigger in vocabulary belonging to the views and
decisions nodes, neither of which exists. The assertions were this node's; the
framing was not.

24 scenarios, six use-case groups, six control-flow graphs. All checks green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
Ownership governance makes produced-by the conductor's write, recorded when a
role produces. The spec-producer ran inline and it went unrecorded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
A fresh cold judge, given no memory of the earlier rounds, returned change and
CONVERGED: no. Oracle passed — the ISP split, per-contract refusal, the views
cut and the separation from the Truss controller/probe contract all held up
under independent re-derivation, and all four acceptance bullets are covered.

Two defects were mine from the start. A Then asserted that the host stores no
approval of its own, which by design is the absence of a store that never
exists, so no verifier can settle it; it now asserts what is observable, that
a decision keeps the state its provider last reported until that provider says
otherwise — the stronger form of the same claim. A barred scenario reached for
an introspection surface declared nowhere; it now calls dispatchAction, the way
its refreshState counterpart already did.

Two were regressions from the previous round editing past what a finding named:
the glossary still carried the cut views contract, and a reworded extension
claimed a divergence the graph has no path to.

The diff is scope-audited: every changed line traces to a named finding, and the
judge's non-blocking note on scenario ordering is left alone on purpose.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
Third cold judge: Oracle and Architect pass, 23 of 24 scenarios pass, one
blocking defect — in the scenario the previous round rewrote.

The rewrite made the assertion observable but never said how the provider
answered the dispatched action, so two implementers could fixture a promptly
accepting provider and a never-settling one and both would pass. The guarantee
was sound; the coverage claim was not. One Given step names the branch, the way
the sibling scenario already did.

The forbidden-combinations prose listed two of the three guards the graph
carries; resolveReference's was covered by CFG and scenario but unnamed there.

The observation that no scenario exercises cross-provider fault isolation is
routed to the plan rather than acted on — it is a strategist-owned question
about a claim in the actors table, not a defect in a scenario.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
Caught in review: the Action graph's `domain returns?` node carried three
outgoing edges, one of them "provider restarted first" — which is the domain
failing to return, not an answer to the question asked. It merged two decisions:
did the provider stay up, and if it answered, did it accept. Split into the
liveness decision and the accept decision, so the unknown outcome now hangs off
the question it actually answers.

Sweeping the rule rather than the instance found two more across the six graphs.
The Bind graph asked "per-contract version compatible?" and answered it three
ways; it now asks how many declared contracts are compatible. The Discover graph
hung labelled branches off an action node with no decision in between.

Scenario-map edge names follow the corrected graphs.

Also adds the two cross-provider fault-isolation scenarios, and narrows the
claim they earn: isolation holds against an incompatible contract within a
domain and against any failure across domains, and stops at the process, since
a provider's contracts share one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
An artifact-set is a kind of thing the repo intends to hold, not a list of
files that happen to exist. Declaring one is an act of intent, so a set may be
empty: the intent is stated and a later change discharges it. That is how a
repo adopts a standard it does not yet meet, and it is the backfill case.

Emptiness is therefore an obligation on the set, never a strain on a
connection — a connection is simply not evaluable until both ends are
populated. Connections are undirected; `between` is a pair, never a source and
a target.

Two sets are declared and empty: cyber-truss has no spec, and command-center
has no code. Both are obligations at different stages.

Drafting this caught a flaw in its own first draft: a "repository structure"
set globbed 2297 files, which is not a kind of thing. Narrowed to the
directories AGENTS.md's Layout table actually names — at which point the
missing docs/adr/ falls straight out as a conformance strain.

Location and schema are backlog C6 and remain open; .truss/lattice.toml is a
proposal, not a settled convention.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
Two stories fall out of the declared-lattice config: a CLI command that writes
and validates a declaration, and a skill that decides what belongs in one. Plus
a real conformance strain the config surfaced — AGENTS.md documents a docs/adr/
that does not exist.

Recorded, not filed. Filing is a separate act and needs permission.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
…nders it

The walking skeleton for cyber-truss#6. The contract had 26 judged scenarios
and no implementation, so nothing had tested whether it survives a real
process. Now it does.

The host discovers providers from a repo-level declaration, spawns each as its
own process, reads a handshake, and checks compatibility per capability
contract rather than per provider — so a provider whose actions contract is
unsupported still binds for state. It holds snapshots it never promotes: when
a provider's process is gone the last snapshot is kept and marked stale, never
deleted and never quietly made live again.

The Truss provider reads two real files, the lattice declaration and the
backlog the model already calls an obligation ledger, and invents nothing. Its
one simulated field is a connection's evaluation status, flagged as a proposal
because held/strained/unevaluated is a backlog item rather than settled model.

Three views: the sets and what must hold between them, the obligations, and a
force-directed graph of the lattice in the terminal. Edges are drawn
undirected, since the glossary bans giving a connection a direction.

Building it corrected the contract twice. `--view` exists because a TUI that
only renders under a TTY cannot be tested; and the empty case had to be a
first-class outcome rather than an error, which is what the declaration's whole
backfill story depends on.

Written implementation-first rather than test-first, against this repo's own
TDD rule. Tests were added after and cover the branches the spec names: partial
bind, refusal, stale-never-live, and a contract the binding does not carry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
…on proved

Verified running in a herdr pane through cyber-mux: all three views and
refresh driven remotely, reading real repository state.

The contract survived a real out-of-process provider unchanged. Actions,
references and the no-replay path are still unexercised, so they should not
freeze on the strength of the spec alone either.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
@changeset-bot

changeset-bot Bot commented Sep 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a83a3d5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
cyber-truss Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

unional and others added 4 commits September 8, 2026 04:44
The single 26-scenario node could not reach either gate. Freeze is per file, so
freezing it whole would fail the impl gate on actions and references that have
no implementation, while not freezing left the landed code ungated. The
partition is what unblocks both, and it follows the iteration boundaries rather
than a guess at sizing.

provider-binding, 16 scenarios: discovery, load, per-contract compatibility,
snapshot freshness, release. Every scenario has running code behind it, so this
is the half that can freeze and then be judged.

provider-exchange, 10 scenarios: references, actions, and the guarantee that an
action whose outcome is unknown is never sent twice. Unbuilt, and it stays in
draft until a slice exercises it.

One scenario changed home. An action in flight when its provider is unloaded
now sits under dispatchAction rather than unloadIntegration, because its
outcome is a property of the action rather than of the release — leaving it
where it was would have split a single decision across two nodes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
The lattice documented two orthogonal axes and instantiated one: all nine
sets were governance targets, so the file demonstrated nothing about the
axis the model leans on hardest. `artifact-sets.mdx` names `{code, test}` as
the canonical unit of change and says outright that code and tests are not
one governance target, "because the criteria governing a test differ from
those governing the code it exercises" -- while this file declared them as
exactly that and nothing else.

Six unit-of-change sets now stand beside the six governance targets, and
two of them overlap the governance targets on the same files, which is the
orthogonality claim made concrete rather than asserted: `cyber-truss
implementation` asks whether a change landed everywhere it had to, while
`cyber-truss code` and `cyber-truss tests` ask whether each conforms, cold.

Held `{code, test}` as one set deliberately, with the reason in the file:
split them and the connection has to be traversed from an end, which is
test-first or code-first, and one set has no traversal order.

Two corrections fall out of the pass. `command-center code` was commented
"declared and unpopulated" and has been populated for some time -- renamed
to `command-center implementation`, since the glob covers its tests too.
And `plugin components` is declared empty against a `files` list that
already promises `skills`, so the emptiness is now a reported obligation
rather than a silent inconsistency.

Verified against the provider: 6 unit-of-change and 6 governance-target
sets parse, the two empty sets raise set obligations, and their connections
report `evaluable: false` naming the unpopulated end.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An installed agent plugin is a copy of a source checkout rather than an npm
install, so its directory has no reliable node_modules and a CLI with external
dependencies cannot run from it. dist/cli.js now inlines commander and runs
with no node_modules present at all.

The library entry keeps its dependencies external so a consumer that also uses
commander shares one copy, and so the public .d.ts keeps referring to types it
can actually resolve.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFKdPvMquYJP5DkcJQ4T5t
Follows the model rename in #15: incompleteness,
obligation, nonconformance. Each now names the defect, so none of the three
reads as a property to be scored, and a strain is exactly one of them.

The comments renamed here arrive with this branch, so they cannot travel in
that PR — `.truss/lattice.toml` does not exist on main yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kFn8pbYyGdDCxEr5SYmks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant