Skip to content

Skill v0.4.1: English unification, integration manifest, topic granularity, reliability guidance#2

Open
SYDeng00 wants to merge 4 commits into
mainfrom
skill-dev
Open

Skill v0.4.1: English unification, integration manifest, topic granularity, reliability guidance#2
SYDeng00 wants to merge 4 commits into
mainfrom
skill-dev

Conversation

@SYDeng00

Copy link
Copy Markdown

Platform-tested skill iteration (uploaded and verified as a test batch before this PR). Contains main's schema-first rules (merged in via c182390) — no content on main is lost.

Corrections

  • uns/create.md: topicType documented as derived from the type folder, not required (explicit param accepted with a deprecation warning); repaired duplicated example sections; aligned type casing guidance with browse.md.
  • All remaining Chinese references translated — the skill is now fully English (19 files), frontmatter descriptions unified.

New guidance

  • Integration manifest (references/core/integration-manifest.md): uns-manifest.yaml declares every recurring publish/consume; declare-before-implement; consumer discover→pin→read workflow; observation-not-authority staleness rule; scope boundary exempting one-off scripts/diagnostics. New SKILL.md doctrine "Every Integration Is Declared" + final-checklist item.
  • Topic granularity (data-integration.md): one topic = one schema = one subscription decision; merge/split criteria as judgment tests; anti-patterns (per-record, per-scalar, mega-topic, DB mirror); advisory count signal (review trigger, not a quota).
  • MQ reliability (mq/quickstart.md): reconnect/resubscribe semantics verified against src/mq/client.ts, clean-session offline loss, history backfill example.
  • Scaffold integration (scaffolds/monoapptemplate.md): long-lived subscriber singleton pattern (globalThis guard, lazy start, graceful shutdown), realtime-data-to-UI guidance.
  • React (openapi/react.md): polling reads for dashboards (useQuery + refetchInterval) with transport-selection boundaries.
  • SKILL.md: troubleshooting index (error message → reference file).

Evals

  • skill-evals/tier0-sdk/eval-battery.md (outside the npm files set): 11 pressure scenarios including negative controls against manifest over-triggering.

Design doc archived in the local workspace (docs/superpowers/specs/2026-07-10-uns-integration-manifest-design.md).

🤖 Generated with Claude Code

SYDeng00 and others added 3 commits July 10, 2026 14:26
…c granularity

Two rounds of improvements packaged as tier0-sdk-v0.4.0 for platform testing.

Corrections and unification:
- uns/create.md: topicType is derived from the type folder, not required
  (legacy explicit param accepted with a warning); repair duplicated
  example sections; align type-casing guidance with browse.md
- Translate all remaining Chinese references to English (uns/*, flow/*,
  react, vue, info, whoami, reload); unify frontmatter descriptions

New guidance:
- mq/quickstart.md: reconnect/reliability semantics verified against
  src/mq/client.ts (auto-reconnect, auto-resubscribe, QoS 1 subscribe,
  clean-session offline loss) + history backfill example
- scaffolds/monoapptemplate.md: long-lived subscriber singleton pattern
  (globalThis guard, lazy start, graceful shutdown) and
  realtime-data-to-UI guidance (server subscribe -> DB -> polling)
- openapi/react.md: polling reads for dashboards (useQuery + refetchInterval)
- SKILL.md: troubleshooting index (error message -> reference file)

Integration manifest and granularity (v0.4.0):
- New core/integration-manifest.md: uns-manifest.yaml declaring every
  recurring publish/consume; declare-before-implement; consumer
  discover->pin->read workflow; observation-not-authority staleness rule;
  scope boundary exempting one-off scripts/diagnostics
- core/data-integration.md: Topic Granularity section — one topic = one
  schema = one subscription decision; merge/split tests; anti-patterns
  (per-record, per-scalar, mega-topic, DB mirror); advisory count signal
- SKILL.md: "Every Integration Is Declared" doctrine, guardrail, final
  checklist item 5

Evals:
- skill-evals/tier0-sdk/eval-battery.md (outside npm files): 11 pressure
  scenarios incl. negative controls against manifest over-triggering

Design doc archived locally (Develop/docs/superpowers/specs/
2026-07-10-uns-integration-manifest-design.md).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts:
#	skills/tier0-sdk/references/core/data-integration.md
#	skills/tier0-sdk/references/mq/quickstart.md
#	skills/tier0-sdk/references/openapi/uns/create.md
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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: c3179afaab

ℹ️ 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 on lines +211 to +213
client.on('connect', async () => {
// Runs on first connect AND every reconnect: fill the gap since the last processed event.
const res = await unsApi.openapiv1unshistory({

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Catch reconnect backfill failures

When the history request fails during a reconnect (for example a transient HTTP error or expired key), this async connect listener rejects, but Tier0MQClient.emit does not await or catch event-listener promises; only subscription message-handler exceptions are caught. In a long-lived subscriber this can surface as an unhandled rejection and terminate or destabilize the worker, so the recommended backfill pattern should wrap the body in try/catch and log/emit the error.

Useful? React with 👍 / 👎.

client.subscribe(TOPIC, (_topic, payload) => {
const evt = JSON.parse(payload);
handleEvent(evt); // idempotent: dedupes by evt.requestId
lastProcessedAt = Math.max(lastProcessedAt, evt.updatedAt ?? Date.now());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the history clock for the backfill cursor

This cursor is later used as history.start_time, but the history endpoint filters by the UNS/VQT timeStamp, not by an arbitrary business field inside the payload. If producers omit WriteItem.timeStamp, or if evt.updatedAt is delayed/ahead due to clock skew, the next reconnect can skip missed records or replay the wrong window; persist and advance the cursor from the UNS history record timeStamp (or explicitly require writers to set timeStamp from the same event clock) instead of deriving it from evt.updatedAt alone.

Useful? React with 👍 / 👎.

topics: [TOPIC],
start_time: new Date(lastProcessedAt).toISOString(),
end_time: new Date().toISOString(),
size: 500,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Page through reconnect history backfills

When the client has been offline long enough for more than 500 events, this example requests a single history page and then processes only results[0].result.values; the history response is paginated (page, size, and total), so records beyond this first page are never replayed. Because this section is the recommended pattern for consumers that must not miss events, it should loop through pages until the gap is exhausted instead of fixing one size: 500 request.

Useful? React with 👍 / 👎.

| Subscribe QoS | Fixed at QoS 1 (at-least-once delivery **while connected**; duplicates possible — dedupe by business key) |
| Publish QoS | Default 0; pass `{ qos: 1 }` or `{ qos: 2 }` per publish when delivery matters |
| Offline gap | **Messages published while the client is disconnected are lost** (clean session — the broker does not queue for offline clients). Reconnect restores the subscription, not the missed messages |
| Handler errors | Exceptions thrown inside a handler are caught and emitted as `error` events; they do not kill the connection |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clarify that async handler rejections are not caught

This guarantee only holds for synchronous throws: Tier0MQClient invokes sub.handler(topic, payloadStr) inside a try/catch but does not await a returned promise, so an async handler that rejects after an await will still become an unhandled rejection unless it catches its own errors. Since subscribers commonly persist events asynchronously, the table should either limit this statement to synchronous handlers or tell users to wrap async handlers in their own try/catch.

Useful? React with 👍 / 👎.

…ct hooks guide

- scaffolds/monoapptemplate.md: publishDeviceMessage example created and
  disconnected a client per publish — a full WebSocket handshake per message,
  contradicting the subscriber singleton on the same page. Now a
  globalThis-guarded shared client, with the one-off-script exception and the
  HTTP-write transport default spelled out (audit K3)
- openapi/react.md: scope banner — these hooks are for standalone SPAs;
  MonoApp scaffold pages go through app API routes with the scaffold's shared
  request hooks (audit K4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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: 540ab07447

ℹ️ 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".

lastProcessedAt = Math.max(lastProcessedAt, evt.updatedAt ?? Date.now());
});

client.on('connect', async () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid backfilling before subscriptions are restored

For reconnects, this connect listener starts the history query before the SDK restores the broker subscription: src/mq/client.ts lines 133-138 emit connect and only then call resubscribeAll(). A message published after this sample's end_time is captured but before the resubscribe completes can be outside the replay window and not delivered live, which breaks the must-not-miss backfill pattern; either backfill after confirmed resubscribe or intentionally overlap/re-run the history window.

Useful? React with 👍 / 👎.

Comment on lines +213 to +215
if (!g[MQ_CLIENT_KEY]) {
const { Tier0MQClient } = await loadTier0Mq();
g[MQ_CLIENT_KEY] = new Tier0MQClient();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Memoize the shared MQ client initialization

When two requests publish during cold start, both can enter this branch before loadTier0Mq() resolves, so each creates a Tier0MQClient; the later assignment overwrites the first and leaves an extra untracked WebSocket connection alive. That defeats the promised one-client-per-process pattern under concurrent first use, so cache an initialization promise or assign a placeholder before the await.

Useful? React with 👍 / 👎.

Comment on lines +69 to +70
Every `topic` value must satisfy the naming contract
(`^.+/(Metric|Action|State)/[^/]+$`, wildcards allowed in consume patterns).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Permit documented broad wildcard subscriptions

When a consumer uses the wildcard subscription pattern documented in references/mq/quickstart.md (Plant/Line1/#) to receive multiple type folders under a branch, this regex rejects the manifest entry because there is no literal Metric|Action|State segment before the leaf. That leaves no compliant way to declare a registered subscription the SDK supports, so agents will either omit it from uns-manifest.yaml or narrow the subscription and miss events; allow broad # consume patterns or remove that subscription pattern from the docs.

Useful? React with 👍 / 👎.

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