Skip to content

feat(resync): notify a live agent when a declared resource carrier changes - #345

Merged
schickling-assistant merged 24 commits into
mainfrom
schickling/2026-08-25-resync
Aug 27, 2026
Merged

feat(resync): notify a live agent when a declared resource carrier changes#345
schickling-assistant merged 24 commits into
mainfrom
schickling/2026-08-25-resync

Conversation

@schickling-assistant

Copy link
Copy Markdown
Contributor

Closes #341. Refs #286 (delivery machinery), #305 (Nix-managed spec composition).

Problem

An agent's context is assembled from its declared resources. When a carrier file changes on disk after launch — configuration management replaced it, a supervisor republished it, Nix activation swapped the goal carrier — the live session keeps acting on the stale version until restart. Nothing tells the agent that a resource it depends on changed.

Goal

A running agent learns, through its normal inbox and DING wake, that one of its declared carriers changed — without restart, without declaration boilerplate, and without waking on noise.

Decisions

Recorded in decision 0008 (settled with the principal over grounded decision requests Q1–Q6 on 2026-08-25):

  • Built-in reserved resync stream (not a declared stream, not a third record kind): reuses the implemented event ingress — ring dedup, receipt validation, producer-side supersession, DING marker — with exactly one carve-out in resolve_stream. Declaring stream "resync" in a spec is refused.
  • Watch scope: local files only — absolute file:// URIs and catalog-relative paths resolved against the agent directory (validate_resource_uri now accepts scheme-less relative paths; st2 extension pending canonical Agent Spec adoption). Other schemes are unwatched by design.
  • Noise model: fixed class defaults in code for v1 — immediate (declaration + goal carriers), silent (agent-authored stores under resources/context|decisions|friction), coalesced (everything else). No notify binding attribute until real volume data justifies the grammar change.
  • Event identity: event-id = SHA-256 of new carrier bytes, key = binding label, always superseded. Equal-byte rewrites deduplicate to no wake; content oscillation notifies honestly.
  • Windows are provisional constants (500 ms / 5 s), tuned by observation per the issue's rollout note.

Verification

New suite tests/resync.rs (all green):

  1. goal-carrier change -> exactly one resync inbox event; equal-content rewrite -> none; write into the context store -> none; changed content -> fresh event under the same key with superseded predecessor.
  2. write-then-rename replacement of agent.kdl -> notifies (parent-directory watch survives inode replacement).
  3. declaring the reserved stream -> refused at discovery.

Full cargo test: 470 lib + 57 agent-spec + integration suites green. Pre-existing failure verified against baseline: agent_publish::incomplete_apply_marker_blocks_declarations_but_not_the_state_plane fails identically on clean HEAD (1da5809) in this environment.

Complexity

One new module (src/resync.rs, ~450 lines incl. tests), two small seams: the reserved-name carve-out in event.rs::resolve_stream and relative-URI acceptance in agent-spec. No new dependencies; watching rides the existing notify backend and mutation-only filter patterns from src/watch.rs.

Concerns

  • Window lengths are guesses until observed on a working catalog (DQ-R1).
  • Classification is static by path role, not by write attribution (RESYNC-T01): an external edit into an agent-authored store is silent by design.
  • Changes missed while the supervisor is down are not reconstructed as events (RESYNC-T03); resume re-seeds silently.

Follow-ups

References

Posted on behalf of @schickling
field value
agent_identity unknown
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.0.3
agent_runtime OMP 18.0.3
tooling_profile dotfiles@a80129b-dirty

@schickling-assistant

Copy link
Copy Markdown
Contributor Author

@codex please review

Posted on behalf of @schickling
field value
agent_identity unknown
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.0.3
agent_runtime OMP 18.0.3
tooling_profile dotfiles@a80129b-dirty

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a6463c72e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/resync.rs
Comment thread src/resync.rs Outdated
Comment thread src/resync.rs
Comment thread src/run.rs Outdated
@schickling-assistant

Copy link
Copy Markdown
Contributor Author

@codex please review the current head

Posted on behalf of @schickling
field value
agent_identity unknown
agent_persona unknown
agent_supervisor unavailable
agent_tool unknown
agent_tool_version unknown
agent_runtime unknown
tooling_profile dotfiles@e4789b0

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 52132aecd2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/resync.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d19223d7f6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/resync.rs
Comment thread src/resync.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5823ea41c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread crates/agent-spec/src/spec.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b30015eacb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/resync.rs Outdated
Comment thread src/resync.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8e8e3f059c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/run.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61d292be0d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/run.rs Outdated
Comment thread src/run.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6b8be04fad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/resync.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04185095ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/run.rs
Comment thread src/resync.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11c6d218a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/resync.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c70d56028b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/resync.rs
Comment thread src/resync.rs
Comment thread src/resync.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: db5cd6b150

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs
Comment thread crates/agent-spec/src/spec.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e566990e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/resync.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 55e0e96d36

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs Outdated
Comment thread src/resync.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ad4b6f54db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/event.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: db2477e684

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/run.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb5c03e045

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/run.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6778ba26c8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/run.rs Outdated
Comment thread crates/agent-spec/src/spec.rs Outdated
@schickling
schickling force-pushed the schickling/2026-08-25-resync branch from 74bcb20 to 0a88ab2 Compare August 27, 2026 13:14

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a88ab2f39

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/run.rs
Comment thread src/resync.rs Outdated
A resource binding uri may now be a scheme-less relative path, resolved by
the consumer against the declaration directory. Absolute URIs keep the
existing validation. This is the carrier form declaratively managed goal
files need (docs/vrs/06-resync); it is an st2 extension pending canonical
Agent Spec adoption.

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@a80129b-dirty
…anges

Implements #341. The supervisor watches each running agent's local resource
carriers (file:// and catalog-relative bindings plus its own declaration),
classifies them (immediate / silent / coalesced), and emits digest-keyed,
superseded events through a built-in reserved `resync` stream on the
unchanged event-stream ingress. Equal-byte rewrites never wake; bursts
coalesce per class window.

Design decisions: docs/vrs/.decisions/0008; subsystem VRS: docs/vrs/06-resync.

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@a80129b-dirty
A reconcile pass can land between a carrier mutation and its flush window
(agent.kdl changes wake reconcile immediately). Reseeding digests on every
watch-set application silently erased that pending event; carriers already on
record now keep their digest and dirty state, and only genuinely unknown
paths seed silently.

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@a80129b-dirty
…periment

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@a80129b-dirty
- run: restore unpark report merging and the crash-loop dedup reset in the
  supervisor loop, lost when the resync wiring landed
- resync: derive the event identity from the whole transition
  (previous digest -> new digest), so an A->B->A oscillation re-notifies on
  the rollback leg instead of colliding with B's original identity
- resync: resolve bus ids with the supervisor's logical host, so hostless
  declarations supervised under `st2 up --host <alias>` produce recipients
  the ingress can actually resolve
- resync: retain every subscriber of a shared carrier path; several agents
  binding one file each get their own event
- resync: carriers whose parent directory cannot be registered fall back to
  digest polling at refresh cadence instead of being watched by nobody

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@a80129b-dirty
schickling-assistant and others added 18 commits August 27, 2026 22:17
…up test

The shell's > redirection creates an empty pidfile before printf writes,
so polling is_file() can observe an empty file under CI load and panic
with ParseIntError::Empty. Poll for parseable content instead.

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@a80129b-dirty
@schickling
schickling force-pushed the schickling/2026-08-25-resync branch from 220b4ad to 410b95e Compare August 27, 2026 20:27
@schickling
schickling force-pushed the schickling/2026-08-25-resync branch from 410b95e to 0708d42 Compare August 27, 2026 20:31
@schickling-assistant
schickling-assistant merged commit dd1e72b into main Aug 27, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0708d42717

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/resync.rs
schickling-assistant added a commit that referenced this pull request Aug 28, 2026
#351 landed first and rewrote R20: a binding's URI scheme is now the exact
lookup key for an optional, catalog-declared Resource Profile, scheme meaning
stays downstream-owned, and st2 ships no built-in profiles.

Drop R35. It existed only because R20 then read "st2 does not register schemes",
which a scheme st2 resolves would have contradicted; it granted an exemption from
a clause R20 no longer contains, so rebasing it would have carried a
self-contradiction into requirements.md. `working-state` needs no exemption under
the merged R20 — st2 writes the carrier through `st2 context`, and resolving the
scheme is a catalog's choice. requirements.md is now identical to main: this
branch makes no constitutional edit.

Decision 0012 records the withdrawal as an amendment rather than rewriting its
history. Nothing about the carrier, its scheme name, or its realization changes.

Renumber this branch's decisions 0008/0009/0010 to 0011/0012/0013; #351 and #345
took 0008 and 0009 on main.

Correct three places that asserted the pre-#351 contract: the ontology's Resource
and working-state entries, and 07-resource/spec.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: Claude Code
agent-tool-version: 2.1.237
agent-runtime: Claude Code 2.1.237
tooling-profile: dotfiles@11eaf2d-dirty
schickling-assistant added a commit that referenced this pull request Aug 28, 2026
#345 admits a catalog-relative carrier path as a binding uri, not only an
absolute URI, and reserves the binding name `declaration` for resync. Three
assertions written against the older contract went stale on the rebase:

- `agent_author` refused `./issue/1` and `example.com/issue/1`; both are valid
  relative carriers now. The refusals worth pinning are the ones that escape the
  catalog (`/etc/passwd`, `../outside`), so those replace them, and a positive
  case pins that `carriers/goal.md` is admitted.
- `agent_resource` asserted a non-absolute uri is refused; it now asserts the
  escaping paths are refused and that the resync-reserved name is refused.
- `agent_publish` drove the retired link-plane `resource add <url>` as a
  state-plane write under an incomplete-apply marker. A binding write is a
  declaration write, so it probes `context append` for the state plane and now
  additionally asserts the marker fences `resource add` — the behaviour that
  moving planes makes correct.

Verified against a same-toolchain `git archive origin/main` baseline: the
branch's failing-target set is a strict subset of main's own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: Claude Code
agent-tool-version: 2.1.237
agent-runtime: Claude Code 2.1.237
tooling-profile: dotfiles@11eaf2d-dirty
schickling pushed a commit that referenced this pull request Aug 28, 2026
…rface (#361)

* docs(vrs): retire the linked-record plane; add R35 st2-owned Resource profiles

st2 carried two disjoint durable edges both called "resource": Agent Spec
Resource bindings, and the link records written by `st2 resource add`. Nothing
in the corpus said they were disjoint, and `ontology.md` — the disambiguation
index that exists to prevent exactly this — defined neither.

Measured on one live catalog of 655 declarations: 889 distinct binding URIs and
233 distinct link-record URLs share zero members, exactly and after
normalization on all five schemes both planes used. The planes are disjoint by
construction — bindings carry what an agent is for, link records carried what it
made — so a shared descriptor type deduplicates nothing.

The link plane was write-only (its only reader was its own `ls`/`read` verb),
adopted by 12.5% of declarations, decaying, and superseded by
`axe work update --artifact/--pty`. It is retired.

The drift between the planes was caused by write-cost asymmetry, not by two
concepts sharing a word: 45 of 241 link records were dependency edges filed in a
products store, because a binding needed publisher authority plus
whole-declaration CAS republication while a link record was one file write.

Adds the 07-resource tree, ontology entries for Resource, Resource binding,
linked record (retired), agent resource directory, and working state, and three
decision records. R35 names the st2-owned Resource profiles that R20's "st2 does
not register schemes" otherwise forbids, so `working-state` can exist without
leaving R20 contradicted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: Claude Code
agent-tool-version: 2.1.237
agent-runtime: Claude Code 2.1.237
tooling-profile: dotfiles@11eaf2d-dirty

* feat(resource): repoint `st2 resource` at declared bindings with mediated writes

`st2 resource` managed link records under `<agent-dir>/resources/links/` — a
plane nothing read, that 12.5% of declarations used, and that `axe work update
--artifact/--pty` has superseded. It is removed, and the verb now reads and
writes the plane that has the spec authority.

    st2 resource ls [<identity>] [--json]
    st2 resource read [<identity>] <name> [--json]
    st2 resource add <name> --uri <uri> --reason <text> [--inactive-reason <text>]
    st2 resource remove <name>
    st2 resource rename <old> <new>

`ls`/`read` project declared bindings; bindings previously had no human surface
at all, which is why agents reaching for `st2 resource ls` measured the other
store. The write verbs do read-modify-CAS-publish internally so the caller never
renders KDL, and they are the fourth caller of the `agent_author` pattern after
streams, desired state, and presentation — full-catalog validation, exact-target
selection, compare-and-swap, fail-closed concurrent change, and the Nix-managed
refusal all come from the existing machinery. A binding-only change does not
relaunch healthy work (R21), and URI bytes are preserved without normalization
(R20).

`<agent-dir>/resources/` is untouched and remains canonical for an agent's
resource files; only `links/` goes.

Two `catalog_apply` tests used `st2 resource add` as a state-plane write probe.
That is now a declaration-plane write, so they probe `context append` and
`message send` instead — the writers that still route through
`with_resolved_state_dir`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: Claude Code
agent-tool-version: 2.1.237
agent-runtime: Claude Code 2.1.237
tooling-profile: dotfiles@11eaf2d-dirty

* fix(resource): drop the dead `links` state-dir entry; correct the ls example ordering

`marker_state_exists` still validated `resources/links` as a real directory. st2
no longer owns that path — the linked-record plane is retired and nothing reads
or writes there — so asserting on it is stale vocabulary. The orphaned
directories remain on disk untouched; st2 simply stops making claims about them.

The 07-resource worked example listed bindings in declaration order. `ls` sorts
by name, which is correct: declaration order has no meaning. Verified against the
real catalog byte-for-byte, including the width-aware name padding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: Claude Code
agent-tool-version: 2.1.237
agent-runtime: Claude Code 2.1.237
tooling-profile: dotfiles@11eaf2d-dirty

* fix(resource): handle a binding's trailing line comment on remove and update

A hand-authored `resource "work" uri="…" reason="…" // why it is here` could not
be removed: `remove_field`'s standalone-line path accepted only whitespace after
the node, so it fell through to the compact path and refused with
`unsafe-source-shape`. The line's own trailing `//` comment is now removable
trivia and goes with the binding it explains. `/*` is deliberately not accepted —
a block comment can span lines and this only ever sees one.

Updating the same binding had a quieter defect: the node span runs to the start
of trailing trivia, so replacing it verbatim glued the rendered node onto the
comment (`reason="Changed."// why`). The separator is now preserved. The output
still parsed, so this was cosmetic rather than corrupting.

Reported by Codex review on #361 (P2). The remove case is the one that hard-failed;
the update case was found while confirming the scope.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: Claude Code
agent-tool-version: 2.1.237
agent-runtime: Claude Code 2.1.237
tooling-profile: dotfiles@11eaf2d-dirty

* docs(vrs): reconcile with the merged Resource Profile foundation

#351 landed first and rewrote R20: a binding's URI scheme is now the exact
lookup key for an optional, catalog-declared Resource Profile, scheme meaning
stays downstream-owned, and st2 ships no built-in profiles.

Drop R35. It existed only because R20 then read "st2 does not register schemes",
which a scheme st2 resolves would have contradicted; it granted an exemption from
a clause R20 no longer contains, so rebasing it would have carried a
self-contradiction into requirements.md. `working-state` needs no exemption under
the merged R20 — st2 writes the carrier through `st2 context`, and resolving the
scheme is a catalog's choice. requirements.md is now identical to main: this
branch makes no constitutional edit.

Decision 0012 records the withdrawal as an amendment rather than rewriting its
history. Nothing about the carrier, its scheme name, or its realization changes.

Renumber this branch's decisions 0008/0009/0010 to 0011/0012/0013; #351 and #345
took 0008 and 0009 on main.

Correct three places that asserted the pre-#351 contract: the ontology's Resource
and working-state entries, and 07-resource/spec.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: Claude Code
agent-tool-version: 2.1.237
agent-runtime: Claude Code 2.1.237
tooling-profile: dotfiles@11eaf2d-dirty

* docs(vrs): scope the resource boundaries to this document, not to st2

"No Resource registry, no generic resolution" described st2 before #351 landed
one. Resolution is out of scope for 07-resource, not absent from st2: the
scheme-keyed profile registry lives in 07-resource-profile. The two are
orthogonal — a binding names a Resource whether or not a profile resolves its
scheme, and `st2 resource` neither reads nor requires one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: Claude Code
agent-tool-version: 2.1.237
agent-runtime: Claude Code 2.1.237
tooling-profile: dotfiles@11eaf2d-dirty

* test: align resource validation coverage with the widened #345 envelope

#345 admits a catalog-relative carrier path as a binding uri, not only an
absolute URI, and reserves the binding name `declaration` for resync. Three
assertions written against the older contract went stale on the rebase:

- `agent_author` refused `./issue/1` and `example.com/issue/1`; both are valid
  relative carriers now. The refusals worth pinning are the ones that escape the
  catalog (`/etc/passwd`, `../outside`), so those replace them, and a positive
  case pins that `carriers/goal.md` is admitted.
- `agent_resource` asserted a non-absolute uri is refused; it now asserts the
  escaping paths are refused and that the resync-reserved name is refused.
- `agent_publish` drove the retired link-plane `resource add <url>` as a
  state-plane write under an incomplete-apply marker. A binding write is a
  declaration write, so it probes `context append` for the state plane and now
  additionally asserts the marker fences `resource add` — the behaviour that
  moving planes makes correct.

Verified against a same-toolchain `git archive origin/main` baseline: the
branch's failing-target set is a strict subset of main's own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: Claude Code
agent-tool-version: 2.1.237
agent-runtime: Claude Code 2.1.237
tooling-profile: dotfiles@11eaf2d-dirty

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

Resync events: notify a live agent when a declared resource carrier changes on disk

2 participants