Skip to content

[AAASM-5663] 🐛 (node-sdk): Make both README quickstart entrypoints run and bind their policy claims - #369

Merged
Chisanan232 merged 14 commits into
mainfrom
v0.0.1/AAASM-5663/fix/readme_entrypoints
Aug 14, 2026
Merged

[AAASM-5663] 🐛 (node-sdk): Make both README quickstart entrypoints run and bind their policy claims#369
Chisanan232 merged 14 commits into
mainfrom
v0.0.1/AAASM-5663/fix/readme_entrypoints

Conversation

@Chisanan232

@Chisanan232 Chisanan232 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Target

  • Task summary:

    The README's two quickstart entrypoints did not run, and the surrounding prose claimed a
    policy check that does not happen in the configuration the README itself documents. Both
    are fixed, along with every same-class claim found in the live docs outside the
    gate-bound quick-start
    . What remains unfixed is enumerated under Found and not fixed
    below — this PR does not claim the class is exhausted.

    AC1 — both entrypoints run as written. Measured by extracting each snippet verbatim
    from the rendered file and executing it.

    Snippet Before After
    README ESM exit 1ConfigurationError: in-process tool enforcement requires a check-capable client… exit 0, prints results for agent assembly
    README CJS exit 1SyntaxError: await is only valid in async functions… exit 0, prints results for agent assembly
    docs/04-guides LangChain exit 1ConfigurationError: No gateway found at http://localhost:7391 exit 0, prints results for agent assembly

    The CJS snippet had two independent defects: the same missing-client config as ESM,
    and top-level await in a CommonJS file — a syntax error that fails before
    initAssembly is ever reached. Fixing only the config would have left it broken.

    AC2 — the policy-check claim. initAssembly was behaving correctly: it refuses to
    route tool checks through the allow-all no-op client rather than pretend to enforce
    (AAASM-3105 / AAASM-4735). The docs were wrong, not the SDK. The snippets now supply the
    gatewayClient that decides the wrapped tools, which makes the claim true rather than
    merely hedged, stated with the ADR 0033 §6 term the configuration earns:
    denied before execution.

    That term is earned, not asserted: §6 admits it for "an SDK shim that honoured a Deny".
    A deny control against the documented config throws PolicyViolationError, and an
    instrumented tool body never printed — the body does not run.

    The fail-closed ConfigurationError is explicitly described as a startup configuration
    check, not a policy decision about a tool
    , so a reader cannot read the refusal as
    enforcement.

  • Task tickets:

    • Task ID: AAASM-5663.
    • Relative task IDs:
      • AAASM-5529 — the quickstart claim-binding gate kept green here.
    • Relative PRs:
      • N/A.
  • Key point change (optional):

    The sweep found more than was reported. The ticket named 2 sites (README ESM + its CJS
    twin). A brace-balanced scan of every initAssembly({…}) block wrapping langchain.tools
    across all live docs found 4 defective blocks, and the same false sentence in
    docs/04-guides/index.md — the very page init-assembly.ts names as "the concrete,
    documented (04-guides LangChain quick-start) vector" for the AAASM-4735 fail-open.

    Pre-fix Post-fix
    Blocks wrapping langchain.tools in live docs 5 5
    …without a deciding client or explicit advisory posture 4 0

    The scan is a positive control, not a claim: run against remote/main it reports the 4
    defective blocks by file and line; run against this branch it reports 0.

Effecting Scope

  • Action Types:

    • ✨ Adding new something
      • 🟢 No breaking change
      • 🟠 Has breaking change
    • ✏️ Modifying existing something
      • 🟢 No breaking change
      • 🟠 Has breaking change
    • 🚮 Removing something
    • 🔧 Fixing bug
    • ♻️ Refactoring something
    • 🍀 Improving something (performance, code quality, security, etc.)
    • 🚀 Release
  • Scopes:

    • 🧩 SDK public API
    • 🪡 API client and transport
    • 🤖 Framework hooks
    • 🫀 Data model and types
    • ⛑️ Error handling
    • 🧪 Testing
      • 🧪 Unit testing
      • 🧪 Integration testing
      • 🧪 End-to-end testing
    • 🚀 Building
      • 🤖 CI/CD
      • 🔗 Dependencies
      • 📦 Project configurations
    • 📚 Documentation
  • Additional description:

    No src/ change — the SDK's behaviour was already correct. The only non-doc edit is the
    justification string on an existing binding in tests/quickstart-claim-bindings.test.ts;
    the bound quote is unchanged, so the gate's whole-sentence equality match is unaffected.

Description

  • README.md — both quickstart snippets now supply a gatewayClient and the CJS one runs
    its sequence inside an async function. Five claim sentences reworded: the Quickstart
    lead-in, the post-snippet paragraph (the one the ticket named), "auto-detects and governs",
    "so every tool call is checked against policy before it runs" under How it works, and
    :405, which credited the core Rust runtime for decisions this SDK may never route to it.
  • docs/03-core-concepts/index.md — "the gateway evaluates each call before it executes",
    the untouched twin of the introduction sentence.
  • docs/07-compatibility-versioning/compatibility.md — "auto-detects and governs",
    left behind on the page the README calls "the authoritative reference".
  • docs/08-troubleshooting/index.md — "the gateway denied the tool call … the
    gateway's reason".
  • docs/04-guides/index.md — the same false sentence and both broken snippets fixed; the
    allow/deny/pending walkthrough now attributes the verdict and reason to the client that
    produces them rather than to a gateway that is not on this path.
  • docs/01-introduction/index.md — the "every tool an agent calls is checked against
    policy before it runs" thesis given the same treatment its audit half already had. A
    later revision of this PR then had to fix a sentence this PR itself introduced: the
    replacement said "wrap tools without such a client and initAssembly refuses to start",
    dropping the langchain.tools conjunct the README version keeps. The refusal fires only
    for explicit langchain.toolstests/auto-detected-noop-enforcement-warning.test.ts
    :59-66 calls initAssembly with no client under default fail-closed enforcement and
    asserts ctx is defined. The plain-terms opener is corrected too; it promised "a
    record of everything it did", which this same file already contradicts at :65-67.
  • tests/quickstart-claim-bindings.test.ts — an existing unproven-claim justification
    cited "both README entrypoints … neither runs as written" as its ground. This PR
    invalidates that premise, so the justification is restated on the ground that still stands.

The first sweep was run on the wrong predicate

The first pass operationalised "the claim class" as a phrase pattern (checked against, before it runs, governs). A claim class is defined by what a sentence
asserts, not by the words it uses, so anything phrased differently was invisible to it.
docs/03-core-concepts/index.md:22 says "the gateway evaluates each call before it
executes" — same assertion, no matching phrase, missed. So did
docs/08-troubleshooting/index.md:66 ("the gateway denied the tool call").

The sweep was redone by reading every live doc against the predicate "asserts that
something evaluated, decided, checked, governed or enforced a call"
. That found four
sites the phrase sweep could not reach, three of which are fixed here and one of which
(README.md:405) nobody had flagged.

Found and NOT fixed — enumerated, not waved past

  • docs/02-quick-start/index.md — carries genuine same-class defects, notably
    :297 ("the gateway's reason") and :309 ("violations recorded as shadow events",
    which the shipped clients discard). Not touched because this file is the one the
    AAASM-5529 gate binds by whole-sentence equality
    ; several of the flagged sentences are
    bound claims. Editing them means rewriting that gate's bindings in lockstep, which is
    AAASM-5529's artifact and a materially larger change than this ticket. Flagging for a
    scope decision rather than unilaterally rewriting a gated file.
  • docs/03-core-concepts/architecture.md:64-70 and 03-core-concepts/index.md:19
    mermaid edges (LC->>GW: policy decision request, GW-->>LC: allow / deny / pending)
    put the gateway on the per-call decision path. The prose beside them is fixed here.
    Whether the diagrams depict the intended architecture or must depict the default runtime
    path is a judgement I did not want to make by redrawing them.
  • docs/05-configuration/index.md:128-129 and 03-core-concepts/index.md:133
    "enforce blocks denied actions" / "observe records would-be violations". These
    describe the core runtime's EnforcementMode posture, which is the semantics sent at
    registration, not a claim about this SDK's in-process path.

Examined and correct as written

  • docs/09-examples/* — verified, not assumed: every page uses withAssembly with a
    supplied client and none calls initAssembly or attributes a decision to "the
    gateway". index.md:23-26 states that scope explicitly.
  • docs/06-api-reference/index.md:27 — scoped to "a gateway client you supply".
  • docs/04-guides/container-base-image.md — "governed out of the box" is qualified by an
    explicit :::note on the same page disclaiming the SDK as an authoritative boundary.
  • docs/03-core-concepts/index.md:57, :59 — negative claims/limitations.
  • docs/07-compatibility-versioning/releasing.md, SECURITY.md, 09-examples/setup.md
    no claims of this class.
  • website/versioned_docs/**36 frozen snapshots of released versions carry the old
    pattern. Not edited: published records of what shipped. AAASM-5676 owns whether retracted
    claims get corrected in frozen snapshots.

Verification

pnpm typecheck and pnpm lint ("ESLint: No issues found") are green. Snippet execution
used a consumer harness resolving @agent-assembly/sdk through the package's real exports
field, so both the ESM and CJS conditions are the ones a reader gets.

No Prettier reformatting is included. prettier --check flags these files, but it flags
remote/main's README.md too — the drift is pre-existing blank-line handling inside the
GENERATED … DO NOT EDIT blocks, no CI job runs a format check, and no hook is installed in
this repo. Reformatting generated blocks is not this ticket's business, so the only edits
here are content.

One limitation, stated plainly: the harness is a source checkout with no prebuilt native
binding, so every run also prints the "agent is NOT registered" warning. That is an artifact
of the checkout, not of the documented config — a reader installing from npm on Linux/macOS
receives a prebuilt binding. It does not affect the defect or the fix, because mode: "auto"
routes to the no-op client whether or not the binding loads.

Both snippets failed on execution. The ESM one wrapped LangChain tools with
no gatewayClient, no mode and a default (fail-closed) enforcementMode, which
trips the AAASM-4735 guard in init-assembly.ts and throws ConfigurationError.
The CJS twin has the same config, and additionally used top-level await in a
CommonJS file — a SyntaxError that fails before initAssembly is ever called,
so fixing the config alone would have left it broken.

Both now supply the gatewayClient that decides the wrapped tools, and the CJS
sequence runs inside an async function. Verified by extracting each snippet
verbatim from this file and executing it: both exit 0.

Refs AAASM-5663
"checked against gateway policy before it runs/before invocation" was false in
the configuration this README documents: with no check-capable client the
wrapper routes through the allow-all no-op client, so nothing is decided. The
sweep found the same claim at three more sites the report did not name — the
Quickstart lead-in, "auto-detects and governs", and "so every tool call is
checked against policy before it runs" under How it works.

All four now name the ADR 0033 §6 term the shown configuration earns, "denied
before execution", and attribute the decision to the gatewayClient rather than
to a gateway that is not in the picture. The fail-closed ConfigurationError is
called a startup configuration check so a reader cannot read the refusal as a
policy decision about a tool. Drops the banned absolutes "every"/"each".

Refs AAASM-5663
…ides them

init-assembly.ts names this page as the concrete documented vector for the
AAASM-4735 fail-open, and it carried the README's defect verbatim: the same
false "every invoke() is checked against gateway policy before it runs"
sentence, plus two snippets that wrap LangChain tools with no gatewayClient.
Executed as written, the first throws ConfigurationError before reaching the
wrap guard because it also omits gatewayUrl.

Both snippets now supply the deciding client and a gateway URL, and the prose
names the ADR 0033 §6 term the configuration earns. "the gateway is consulted
on every call" becomes what the wrapper actually does — ask the configured
client — since no gateway is consulted on this path.

Refs AAASM-5663
"every tool an agent calls is checked against policy before it runs" is the
same claim the README made and is false on the default path. The paragraph
after it already qualified the audit half honestly (AAASM-5681); this gives
the enforcement half the same treatment and drops the banned absolute.

Refs AAASM-5663
The prose added for this ticket reintroduced the fd-7 absolutes it was meant
to remove ("Decides every wrapped invoke()", "each tool is wrapped"). Reworded
to state what the wrapper does without quantifying over calls.

The 04-guides paragraph on the fail-closed refusal also restated the
":::note[In-process tool enforcement needs a check-capable mode]" admonition
sitting directly under the same snippet; replaced with a pointer to it.

Refs AAASM-5663
…dated

The AAASM-5529 gate registered "The SDK enforces policy by talking to an Agent
Assembly gateway" as unproven, justified by the README entrypoints not running
as written. That premise no longer holds once this ticket fixes them, so the
justification is restated on the ground that still stands: the controls decide
tool calls through a caller-supplied gatewayClient answering in-process, which
proves a wrapped call is decided before its body runs, not that a gateway is
the deciding party.

The quote is unchanged, so the gate's whole-sentence equality match is
unaffected.

Refs AAASM-5663
…es it

The allow/deny/pending walkthrough still credited "the gateway" for the
verdict and the reason string, one paragraph below the sentence corrected
earlier in this ticket. On this path the decision comes from the configured
gatewayClient, so the surrounding text now says so consistently.

Refs AAASM-5663
…lkthrough

"The SDK wraps each tool so the gateway sees the call first" is the same
misattribution corrected elsewhere in this ticket, sitting three paragraphs
below one of those corrections. On this path the deciding party is the
configured gateway client, not a gateway.

Also rewraps the Framework-compatibility line this ticket had pushed past the
file's wrap width.

Refs AAASM-5663
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

The reason on "The SDK enforces policy by talking to an Agent Assembly
gateway" is a FORWARD pointer — "no control covers a reader actually reaching
a gateway" — not a citation for where the claim was last examined. Naming
AAASM-5663 sent a reader to a ticket that fixes README snippets and never
intended to deliver gateway coverage, and that pointer goes stale the moment
this work merges.

AAASM-5758 ("CI job running each documented SDK quick-start from a clean
environment, using published artifacts only") owns the gap, is still open, and
carries the node-sdk, python-sdk and go-sdk components — so the three SDKs name
one referent rather than three. It lists AAASM-5663 among its blockers, which
is the right direction: this ticket unblocks that one.

The reason now says outright that it is a forward pointer, so the next reader
does not have to infer which kind of reference it is. The bound quote is
unchanged, so the gate's whole-sentence equality match is unaffected.

Refs AAASM-5663, AAASM-5758
…roduction

A sentence THIS BRANCH added was false. "wrap tools without such a client and
initAssembly refuses to start" is unscoped, but the refusal fires only for
explicit langchain.tools: wrapsToolsThroughGatewayClient (init-assembly.ts
:217-220) reads config.langchain?.tools and nothing else, and the guard at
:755-762 is &&-gated on it. init-assembly.ts:538-540 states the opposite for
everything else — auto-detected frameworks have no init-time throw.

An in-repo control falsifies the sentence directly: tests/auto-detected-noop-
enforcement-warning.test.ts:59-66 calls initAssembly with no gatewayClient
under default fail-closed enforcement and asserts ctx IS defined. The README
paragraph keeps the langchain.tools conjunct because it opens on it; dropping
it here made a true sentence false.

Now scoped, and says what the other path does instead: it warns and proceeds.

Also corrects the plain-terms opener, which promised "an agent can only do what
your rules allow" and "a record of everything it did" — both false on the
default path, and both already contradicted by this file's own lines 34-38 and
65-67. The opener now defers to them instead of contradicting them.

Refs AAASM-5663
"the tools you handed it are wrapped so the gateway evaluates each call before
it executes" is the untouched twin of the introduction sentence already fixed
under this ticket. No gateway evaluates anything on the default path — the
fallback client answers in-process and allows everything.

The mermaid flowchart directly above draws SDK to aa-ffi-node to gateway, so
the sentence reads as a product claim rather than a description of one
configuration; the replacement says which path the diagram depicts and what
the fallback client does instead.

Refs AAASM-5663
Byte-for-byte the sentence already corrected in the README, left behind on the
page README.md:213-214 calls "the authoritative reference" — so the derived
copy was fixed and the authoritative one was not. "Governs" is exactly the
undifferentiated verb ADR 0033 §6 tells downstream material not to use.

Refs AAASM-5663
…d it

"the gateway denied the tool call ... the gateway's reason" is the same
misattribution corrected in 04-guides, phrased differently enough that a
phrase-pattern sweep did not reach it. Found by reading the file.

Refs AAASM-5663
…not route

"The governance decisions it enforces are made by the core Rust runtime" is
false in the configuration this README now documents, where the decision comes
from a caller-supplied client answering in-process. Narrowed to the
authoritative decisions, which is the claim that holds.

Refs AAASM-5663
@sonarqubecloud

Copy link
Copy Markdown

@Chisanan232
Chisanan232 merged commit a58c996 into main Aug 14, 2026
27 checks passed
@Chisanan232
Chisanan232 deleted the v0.0.1/AAASM-5663/fix/readme_entrypoints branch August 14, 2026 03:43
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