Observed rather than assumed, after checking the running instance:
collections carry per-user permissions in three tiers and permissions
are collection-scoped, not per-document. So one collection per writing
principal, with read membership for everyone else.
- States precisely what that enforces: no other agent can write a
given agent's world model. It does not enforce operator-versus-agent
exclusion, since the operator holds manager on their own wiki; that
half is procedural, via the break-glass routine that stops the
agents first. Two different strengths, so the spec no longer implies
one guarantee covers both
- Per-user grants, not groups: Outline groups are not federated with
LLDAP, so using them would put membership somewhere nothing syncs.
Three principals make the manual mapping trivial
- Outline API keys are per-user, so each agent's token must belong to
that agent's own Outline user. A token minted from an admin account
voids every boundary above while appearing to work — the same shape
as the Gitea permission surprise
- Collections identified by ID from config, documents by ID recorded
in the state store, which also makes writes idempotent across a
retry
- The conditional-write requirement softens to a revision *read*:
break-glass stops the agents, so compare-and-swap is unnecessary and
only divergence detection is needed for A3
Also records Outline's MCP server as considered and deferred. A17's
enforcement depends on this library sitting between the model and the
store; MCP's purpose is direct model access, and a procedure the model
may decline to fetch does not constrain it. Still a candidate for the
discretionary search tool, with two things to verify first.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two loose ends in the A17 amendment, both found by asking whether the
build order needed changing:
- A17 requires retrieved content to be snapshotted into the canonical
log, but A10's event table — the authoritative list — had no row for
it, so an implementer reading A10 would never know to add one.
knowledge_retrieved now carries the text as read, the document ID,
its revision, and when it was read
- Part G step 10 already scheduled Outline, so the ordering does not
change; it now names A17 rather than only Part D, and says which
half arrives first — the world model, with operator procedures
waiting on the C2 taxonomy they bind to
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Part D said what Outline is for but never how to build against it —
the only external integration with no A-series component, while
Transport, LLM, Browser, Secrets, SSO and Logging all have one. A17
supplies the contract.
Settled here:
- Sharing is read access, never write access. Every document has
exactly one writer, so concurrent writers never exist and Part D's
last-write-wins objection disposes of itself. Default shared
membership is operator + nisse-ops; nisse-dev gets private space
only, since B3 seals it from the LAN and a shared network map is a
map of what it is sealed from
- Agent-owned knowledge is always a cache, never authority: rely on
it to know what exists and where to look, verify a specific fact
against the live system before acting on it
- Enforcement is structural, because a prompt is not enforcement. A
model cannot be stopped from believing what it reads, so the
enforceable goal is narrower — an unverified belief must not become
an irreversible action — and four mechanisms carry it, leaning
hardest on surfacing provenance at the human gate that C2 already
requires
- Never an instruction channel and never an approval channel, stated
both here and in A4 where approvals are specified
- Corrections flow through transport rather than direct edits, which
is better provenance: a hand edit is invisible to the agent's
record, an instruction is authenticated, logged, and reconcilable.
Break-glass reuses Part F's idle flag
- Retrieved content is snapshotted into the canonical log, since A10
forbids a mutable provider handle being the only reference — with
the A3 consequence that boot must re-fetch snapshots for resumed
tasks
- Outage posture is asymmetric: write failures never block, but a
failed read of a procedure bound to a confirm-first action gates,
because proceeding is acting unconstrained on exactly the operation
someone wrote a procedure for
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
B2 specified the service account and its scoped token but never said
the project repo's default branch must be protected — which turns out
to be the load-bearing part of the PR gate.
In Gitea, write access includes merging pull requests, and repository
ownership does not restrict merging either. So an agent with the
access it needs to push branches can also merge its own PR, and the
review gate holds only because the agent's code does not call the
merge endpoint. That is the advisory guarantee A4 exists to rule out.
Verified rather than assumed: before protection was configured, the
agent's own token merged its own PR (HTTP 200). With protection it is
refused (405), as is a direct push to the default branch. The
amendment says to assert both, so relaxing the protection later fails
a test instead of silently removing the gate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every durable mutation emits one JSON-lines event, emitted by the
state store itself immediately after the commit returns, with a fixed
envelope (ts, agent, event, task_id correlation ID, cause) and a
dotted event taxonomy covering transitions, intents, gates, boot
reconciliation, and migrations. Logs stay diagnostic-only, never
load-bearing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Part H's repository-layout item is resolved: one repo, three packages.
Naming (S0), scope (S0.1), the step-10 extraction, and the repository
layout section are updated to match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Seeds nisse-core as the home for system-level design documentation. The
spec covers the shared library (Part A), both agents (Parts B and C), and
the supporting services, build order, and open decisions.
nisse-core holds this because the document describes the shared design
rather than either agent's implementation; the repo gains code later, at
the extraction step in the build order.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>