[PR #5664] [MERGED] feat(analysis-view): share templated positions across manifest tools #7021

Closed
opened 2026-11-01 21:44:47 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/5664
Author: @earakely-scale
Created: 10/20/2026
Status: ✅ Merged
Merged: 10/21/2026
Merged by: @morluto

Base: main ← Head: feat/manifest-item-write-templates


📝 Commits (10+)

  • c4b4302 docs(specs): plan a template rule that shares templated positions
  • 6d8aa4b feat(analysis-view): share templated positions across manifest tools
  • 72fbed5 refactor(analysis-view): drop the unused ManifestRule alias
  • 930c96d docs(specs): record the prefix-variance checks and corpus results
  • 33b0643 fix(analysis-view): share positions with digit-free generated identifiers
  • 9a025b3 docs(specs): record five environments rebuilt end to end with the rule
  • 6ef39ec chore: merge main (52c84f6f) into the prefix-variance branch
  • 75af11f fix(analysis-view): share a position with the parameter that observed the literal
  • 6a8beb5 docs(specs): record the prefix-variance review round
  • 03b66df fix(analysis-view): bound the spelling summary of shared positions

📊 Changes

13 files changed (+962 additions, -196 deletions)

View changed files

➕ docs/specs/agent-environments/prefix-variance/plan.md (+18 -0)
➕ docs/specs/agent-environments/prefix-variance/spec.md (+59 -0)
➕ docs/specs/agent-environments/prefix-variance/tasks.md (+10 -0)
➕ docs/specs/agent-environments/prefix-variance/verification.md (+149 -0)
📝 docs/web-network-captures.md (+18 -7)
📝 src/domain/analysisView/EnvironmentManifestAccumulator.ts (+11 -10)
➕ src/domain/analysisView/environmentManifestNames.ts (+157 -0)
📝 src/domain/analysisView/environmentManifestRules.test.ts (+1 -1)
📝 src/domain/analysisView/environmentManifestRules.ts (+182 -177)
➕ src/domain/analysisView/environmentManifestSpelling.test.ts (+29 -0)
➕ src/domain/analysisView/environmentManifestSpelling.ts (+84 -0)
📝 src/domain/analysisView/environmentManifestView.test.ts (+243 -0)
📝 src/domain/analysisView/environmentManifestView.ts (+1 -1)

📄 Description

Summary

A capture session usually edits one scratch entity: it creates it, then updates and deletes it at a fixed path such as /api/v1/collections/0RZ576QZQA5KG. The environment manifest templates a segment only when sibling routes of the same method and segment count vary there. So those writes stay literal single-entity tools (patch_collections_0rz576qzqa5kg), even though the reads of the same collection were templated as /api/v1/collections/{collection_id}.

This PR adds an opt-in template rule, prefix-variance. It templates such a literal with the parameter another tool already uses at that position, so the write becomes patch_collections_by_collection_id on the read's exact template.

Part of #4933. Spec, plan, tasks and verification are in docs/specs/agent-environments/prefix-variance/.

Problem and expected behavior

A literal write tool addresses one entity that may not exist in any later state. Nothing can model its effect. The write-effects gate in #5600 reports these tools as no-state-target, and they were the largest group it could not serve.

With the rule listed in template_rules:

  • When it applies: a literal at position p is templated when another tool on the same origin has a parameter at p from one of the other opt-in rules, after the same preceding parts. The other tool can have any method and any segment count, so deeper routes such as …/collections/{collection_id}/books are covered too.

  • Which literals qualify:

    • one of the values any such tool observed at that position;
    • a literal that carries a digit and has the length and character classes (digits, lower case, upper case, each other character) of an observed value; or
    • when every observed value has one length of eight or more characters, as generated ids often do, a literal of that length using only their character classes, so an id that happens to hold no digit still qualifies. This clause was added after the end-to-end runs below.

    Empty literals, stop words and v1-style versions never qualify, and format-rule positions ({numeric}, …) are never shared.

  • Naming: the parameter takes the shared parameter's name (collection_id, uid, a pair's _namespace and _name) and is labelled prefix-variance.

  • Merging: tools whose routes now match merge, and a merged position keeps a tool's own rule when one templated it.

  • Segment limit: like the sibling rules, it compares routes of at most 32 segments and says so in a limitation.

Change and scope

  • Rule placement: environmentManifestRules.ts gains the pass. It runs last, so it can share every parameter the other rules produce.
  • Recorded rule: a prefix-variance parameter records the rule it shares (sharedRule), which both names it and keys it when routes are compared.
  • Supporting refactors:
    • tool naming moves to environmentManifestNames.ts, so the rules file stays under the length limit;
    • the three comparing passes share the 32-segment split;
    • the segment-limited rules are listed once.
  • Not included:
    • no change to the default rules or to any other rule;
    • no templating from response bodies;
    • no change to which groups are excluded.
  • Follow-up found: writes whose response has no body and no content type outside /api/ are still excluded as non-json. That hides 13 write tools in 5 of the showcase captures (Directus, Jellyfin, Keycloak, Miniflux, Shlink). Fixing it changes default output, so it belongs in a separate change.

Within the contribution scope: an analysis-view projection change inside an existing boundary; no target execution.

Contract and boundary impact

  • Semantic owner and earliest changed stage: the environment-manifest analysis view (src/domain/analysisView/), at template-rule application.
  • Contribution scope fit and linked maintainer decision: an opt-in rule within the existing view; not applicable.
  • CLI and MCP/tool-catalog contract: template_rules accepts prefix-variance. The request schema's description names it, which changes the generated tool catalog. Tool params[].rule can now be prefix-variance. Requests that don't list it give identical results.
  • Provider, bridge, target-format, or platform compatibility: none.
  • Evidence, artifact, provenance, or reconstruction contract: the manifest is still derived from request lines only; every merged parameter stays basis: "inferred", with its observed values.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none beyond the generated MCP catalog.

Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

Tests added. Seven cases in environmentManifestView.test.ts:

  • a literal shared across methods and depths, plus the same capture without the rule;
  • the spelling condition: same classes and length, case, a missing digit, a colon word, a version;
  • a digit-free member of a fixed-length id family, against a shorter word, a hyphenated value and a family shorter than eight characters;
  • merges that keep a tool's own rule;
  • both halves of a templated pair;
  • format-rule positions;
  • the segment limit and its limitation.

Corpus evidence (executed over the 50 showcase captures: 45 HAR inspections, 5 browser scenarios):

  • Unchanged without the rule. Main's build and this branch give byte-identical results without the rule: the manifest with no rules, with the four existing opt-in rules, and the environment-state view. All 150 of 150 hash equal.

  • Templated with the rule. Added to after-uid-literal, opaque-token and sibling-variance, the rule templates 25 literal write tools and 44 read tools in 10 captures:

    • Komga: collections, readlists, book pages;
    • n8n: workflow PATCH, DELETE, archive, and the reads of a workflow whose id holds no digit;
    • Memos: memos, user reads, and the reads of two memos whose ids hold no digit;
    • Navidrome: playlists;
    • Mealie: recipes;
    • Grist: documents, table records;
    • Redpanda Console: subjects, topics;
    • Sentry: releases;
    • Shlink: short URLs;
    • Mattermost: me reads.

    Tools go from 1,591 to 1,578, because Redpanda Console's per-subject reads and the per-memo and per-workflow reads merge.

  • Left alone, as intended: Espo CRM layout, Federal Register facets, Ghost slug, Shlink stats, Lychee Metrics::photo and Vault's path names.

  • Combined with #5600 (merged locally with main):

    • served write tools go from 33 to 39: Komga collection create, update and delete; n8n workflow delete; Sentry release update and delete;
    • write tools with no state target go from 102 to 87.
  • Newly modelled but still unserved, because of what the capture holds:

    • no read after the write: Komga readlists, Mealie, Navidrome, Redpanda Console;
    • n8n's item read shows an expanded shared relation its create response never returned;
    • Shlink sorts tags while the update echoes the request's order.

End to end on five random environments. Komga, Mealie, n8n, Sentry and Shlink were drawn at random from the ten environments the rule changes, redrawing until one had newly served writes. Each was rebuilt on its own Linux VM from its published scoped HAR with npm pack of #5600 + main + this branch: manifest, bundle, smoke, retrieval tasks for gpt-oss-120b and GLM-5.3-Flash, write tasks graded from the state through data/get, and a dry-run dataset. Published results are in brackets.

Environment Tools Served from state (reads / writes) Retrieval gpt-oss Retrieval GLM Writes gpt-oss Writes GLM
Komga 42 → 46 26 / 3 12/12 (11/12) 12/12 (11/12) 3/4 4/4
Mealie 39 → 39 36 / 0 12/12 (12/12) 12/12 (12/12) – –
n8n 30 → 33 17 / 1 9/9 (9/9) 9/9 (9/9) 2/2 2/2
Sentry 34 → 34 26 / 3 12/12 (12/12) 11/12 (12/12) 2/4, rerun 0/4 4/4
Shlink 17 → 17 5 / 0 5/7, rerun 7/7 7/7 (7/7) – –

Every smoke task passed. The misses:

  • Sentry writes with gpt-oss: in every failed episode the model passed id: "sentry" for the /api/0/ segment, which the tool schema describes as observed: 0. Every passing episode, and every GLM episode, passed 0.
  • Komga's update and Shlink's first run with gpt-oss: the provider rejected malformed tool calls (null or undefined optional arguments).
  • Sentry qa-03 with GLM: the model never called the alert-rules tool.

The first n8n run showed that a digit-free workflow id stayed literal: reading that workflow by id failed because the state held only its list fields. The fixed-length clause fixed that, and the rebuilt n8n reads it correctly.

Live comparison, seeded by the same scripts:

  • Komga 1.29.1: 9 of 12 steps equal. Collection create, update, delete and the reads after them agree apart from the generated id. Two differences remain: the collection list after a create omits the new collection (recorded membership), and a deleted collection's 404 replays the recorded body.

  • n8n 1.123.85: 3 of 8 steps equal.

    • n8n refuses to delete a workflow that isn't archived (400); the environment deletes it.
    • The workflow list replays its recorded response, so deletes don't show in it.
    • Archiving isn't served.

    These gaps belong to the write and list serving in #5600 and its base, not to this rule.

User-visible output. Komga, with the rule:

{
  "name": "patch_collections_by_collection_id",
  "method": "PATCH",
  "path_template": "/api/v1/collections/{collection_id}",
  "api_surface_template": "/api/v1/collections/0RZ576QZQA5KG",
  "params": [
    {
      "index": 3,
      "name": "collection_id",
      "rule": "prefix-variance",
      "basis": "inferred",
      "observed_values": ["0RZ576QZQA5KG"]
    }
  ],
  "body_shape": { "type": "object", "properties": { "name": "string", "ordered": "boolean" } },
  "statuses": [204],
  "record_ordinals": [108]
}

Without the rule the same record is patch_collections_0rz576qzqa5kg with params: [].

Remaining proof gaps. The rule is an inference from paths. An app whose identifier-like literal sits beside an opt-in parameter but names a different resource would be templated wrongly. In the 50 captures, every such literal that qualified was the same resource, and every one that didn't qualify was a word.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

Run on macOS with Node v22.23.1 at 33b0643e (the rule, the alias removal, and the fixed-length clause); 9a025b32 adds only the verification record.

  • npm run build:cached, npm run check:fast, npm run format:check, npm run scan:todos, npm run docs:check, npm run verify:test-discovery, npm run mcp-catalog:check: passed.
  • npx knip: passed.
  • npm run jscpd: 3.49% over 3561 files, 3067 clones. Main is 3.49% with 3068.
  • npx vitest run --project domain --project services: 7119 passed, 5 pre-existing skips.
  • npm run test:prepare, then npm run test:focused -- the analysis-view MCP and CLI boundaries, compact input schema, tool schema validity, and environment serve and export boundaries: 7 files, 76 passed.
  • npx vitest run src/domain/analysisView/: 280 passed.
  • Main's build and this branch's give identical outputs without the rule: 150 of 150 over the 50 captures, rechecked at 33b0643e.
  • Review round (head 6a8beb58): merged main at 52c84f6f, then fixed the five bot threads in 75af11fd. Shared values stay with the parameter that observed them, each donor's spelling is summarised once, and one observation forms a fixed-length family. Both new tests fail on the previous head. The gates above passed again (domain and services 7255, 5 pre-existing skips; focused boundaries 76; jscpd 3.49%), and the tools with and without prefix-variance over the 50 captures are unchanged, name for name.
  • Review round 2 (head 03b66df9): bounded the spelling summary for Codex's follow-up: characters are classified in one pass, and a value over 128 characters is compared only exactly. Its test fails on 6a8beb58; the gates passed again (domain and services 7257, focused boundaries 76, jscpd 3.49%), and the census over the 50 captures is unchanged.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. The rule is opt-in, and outputs without it are unchanged.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: request lines only; no bodies or headers are read by the rule.

Author readiness

Human owner:

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/5664 **Author:** [@earakely-scale](https://github.com/earakely-scale) **Created:** 10/20/2026 **Status:** ✅ Merged **Merged:** 10/21/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `feat/manifest-item-write-templates` --- ### 📝 Commits (10+) - [`c4b4302`](https://github.com/morluto/rea/commit/c4b430252e8295393e4c69c19010ba497994ccde) docs(specs): plan a template rule that shares templated positions - [`6d8aa4b`](https://github.com/morluto/rea/commit/6d8aa4b725093cc1be9e337437576eed9df08155) feat(analysis-view): share templated positions across manifest tools - [`72fbed5`](https://github.com/morluto/rea/commit/72fbed5393269164a377f90b2b47ad04a2a51cfd) refactor(analysis-view): drop the unused ManifestRule alias - [`930c96d`](https://github.com/morluto/rea/commit/930c96d0a1095e5b03c532b5d780c8c0542f077f) docs(specs): record the prefix-variance checks and corpus results - [`33b0643`](https://github.com/morluto/rea/commit/33b0643e8cc173dae1766cb01062fcf0e56cf3dc) fix(analysis-view): share positions with digit-free generated identifiers - [`9a025b3`](https://github.com/morluto/rea/commit/9a025b3260a32f57e72781ae78a94c0c085870f3) docs(specs): record five environments rebuilt end to end with the rule - [`6ef39ec`](https://github.com/morluto/rea/commit/6ef39ec401a2dedc2470b23c486c39721c4060fa) chore: merge main (52c84f6f) into the prefix-variance branch - [`75af11f`](https://github.com/morluto/rea/commit/75af11fd840987e12071cec1dcceabbf8f0143ad) fix(analysis-view): share a position with the parameter that observed the literal - [`6a8beb5`](https://github.com/morluto/rea/commit/6a8beb589adf580130321653f826ff4a1f3adc41) docs(specs): record the prefix-variance review round - [`03b66df`](https://github.com/morluto/rea/commit/03b66df90301a146627a9c025eb6fd41d76b4161) fix(analysis-view): bound the spelling summary of shared positions ### 📊 Changes **13 files changed** (+962 additions, -196 deletions) <details> <summary>View changed files</summary> ➕ `docs/specs/agent-environments/prefix-variance/plan.md` (+18 -0) ➕ `docs/specs/agent-environments/prefix-variance/spec.md` (+59 -0) ➕ `docs/specs/agent-environments/prefix-variance/tasks.md` (+10 -0) ➕ `docs/specs/agent-environments/prefix-variance/verification.md` (+149 -0) 📝 `docs/web-network-captures.md` (+18 -7) 📝 `src/domain/analysisView/EnvironmentManifestAccumulator.ts` (+11 -10) ➕ `src/domain/analysisView/environmentManifestNames.ts` (+157 -0) 📝 `src/domain/analysisView/environmentManifestRules.test.ts` (+1 -1) 📝 `src/domain/analysisView/environmentManifestRules.ts` (+182 -177) ➕ `src/domain/analysisView/environmentManifestSpelling.test.ts` (+29 -0) ➕ `src/domain/analysisView/environmentManifestSpelling.ts` (+84 -0) 📝 `src/domain/analysisView/environmentManifestView.test.ts` (+243 -0) 📝 `src/domain/analysisView/environmentManifestView.ts` (+1 -1) </details> ### 📄 Description ## Summary A capture session usually edits one scratch entity: it creates it, then updates and deletes it at a fixed path such as `/api/v1/collections/0RZ576QZQA5KG`. The environment manifest templates a segment only when sibling routes of the same method and segment count vary there. So those writes stay literal single-entity tools (`patch_collections_0rz576qzqa5kg`), even though the reads of the same collection were templated as `/api/v1/collections/{collection_id}`. This PR adds an opt-in template rule, `prefix-variance`. It templates such a literal with the parameter another tool already uses at that position, so the write becomes `patch_collections_by_collection_id` on the read's exact template. Part of #4933. Spec, plan, tasks and verification are in `docs/specs/agent-environments/prefix-variance/`. ## Problem and expected behavior A literal write tool addresses one entity that may not exist in any later state. Nothing can model its effect. The write-effects gate in #5600 reports these tools as `no-state-target`, and they were the largest group it could not serve. With the rule listed in `template_rules`: - **When it applies:** a literal at position `p` is templated when another tool on the same origin has a parameter at `p` from one of the other opt-in rules, after the same preceding parts. The other tool can have any method and any segment count, so deeper routes such as `…/collections/{collection_id}/books` are covered too. - **Which literals qualify:** - one of the values any such tool observed at that position; - a literal that carries a digit and has the length and character classes (digits, lower case, upper case, each other character) of an observed value; or - when every observed value has one length of eight or more characters, as generated ids often do, a literal of that length using only their character classes, so an id that happens to hold no digit still qualifies. This clause was added after the end-to-end runs below. Empty literals, stop words and `v1`-style versions never qualify, and format-rule positions (`{numeric}`, …) are never shared. - **Naming:** the parameter takes the shared parameter's name (`collection_id`, `uid`, a pair's `_namespace` and `_name`) and is labelled `prefix-variance`. - **Merging:** tools whose routes now match merge, and a merged position keeps a tool's own rule when one templated it. - **Segment limit:** like the sibling rules, it compares routes of at most 32 segments and says so in a limitation. ## Change and scope - **Rule placement:** `environmentManifestRules.ts` gains the pass. It runs last, so it can share every parameter the other rules produce. - **Recorded rule:** a `prefix-variance` parameter records the rule it shares (`sharedRule`), which both names it and keys it when routes are compared. - **Supporting refactors:** - tool naming moves to `environmentManifestNames.ts`, so the rules file stays under the length limit; - the three comparing passes share the 32-segment split; - the segment-limited rules are listed once. - **Not included:** - no change to the default rules or to any other rule; - no templating from response bodies; - no change to which groups are excluded. - **Follow-up found:** writes whose response has no body and no content type outside `/api/` are still excluded as `non-json`. That hides 13 write tools in 5 of the showcase captures (Directus, Jellyfin, Keycloak, Miniflux, Shlink). Fixing it changes default output, so it belongs in a separate change. Within the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope): an analysis-view projection change inside an existing boundary; no target execution. ## Contract and boundary impact - Semantic owner and earliest changed stage: the environment-manifest analysis view (`src/domain/analysisView/`), at template-rule application. - Contribution scope fit and linked maintainer decision: an opt-in rule within the existing view; not applicable. - CLI and MCP/tool-catalog contract: `template_rules` accepts `prefix-variance`. The request schema's description names it, which changes the generated tool catalog. Tool `params[].rule` can now be `prefix-variance`. Requests that don't list it give identical results. - Provider, bridge, target-format, or platform compatibility: none. - Evidence, artifact, provenance, or reconstruction contract: the manifest is still derived from request lines only; every merged parameter stays `basis: "inferred"`, with its observed values. - Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none beyond the generated MCP catalog. Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage **Tests added.** Seven cases in `environmentManifestView.test.ts`: - a literal shared across methods and depths, plus the same capture without the rule; - the spelling condition: same classes and length, case, a missing digit, a colon word, a version; - a digit-free member of a fixed-length id family, against a shorter word, a hyphenated value and a family shorter than eight characters; - merges that keep a tool's own rule; - both halves of a templated pair; - format-rule positions; - the segment limit and its limitation. **Corpus evidence** (executed over the 50 showcase captures: 45 HAR inspections, 5 browser scenarios): - **Unchanged without the rule.** Main's build and this branch give byte-identical results without the rule: the manifest with no rules, with the four existing opt-in rules, and the environment-state view. All 150 of 150 hash equal. - **Templated with the rule.** Added to `after-uid-literal`, `opaque-token` and `sibling-variance`, the rule templates 25 literal write tools and 44 read tools in 10 captures: - Komga: collections, readlists, book pages; - n8n: workflow `PATCH`, `DELETE`, archive, and the reads of a workflow whose id holds no digit; - Memos: memos, user reads, and the reads of two memos whose ids hold no digit; - Navidrome: playlists; - Mealie: recipes; - Grist: documents, table records; - Redpanda Console: subjects, topics; - Sentry: releases; - Shlink: short URLs; - Mattermost: `me` reads. Tools go from 1,591 to 1,578, because Redpanda Console's per-subject reads and the per-memo and per-workflow reads merge. - **Left alone, as intended:** Espo CRM `layout`, Federal Register `facets`, Ghost `slug`, Shlink `stats`, Lychee `Metrics::photo` and Vault's path names. - **Combined with #5600** (merged locally with main): - served write tools go from 33 to 39: Komga collection create, update and delete; n8n workflow delete; Sentry release update and delete; - write tools with no state target go from 102 to 87. - **Newly modelled but still unserved**, because of what the capture holds: - no read after the write: Komga readlists, Mealie, Navidrome, Redpanda Console; - n8n's item read shows an expanded `shared` relation its create response never returned; - Shlink sorts `tags` while the update echoes the request's order. **End to end on five random environments.** Komga, Mealie, n8n, Sentry and Shlink were drawn at random from the ten environments the rule changes, redrawing until one had newly served writes. Each was rebuilt on its own Linux VM from its published scoped HAR with `npm pack` of #5600 + main + this branch: manifest, bundle, smoke, retrieval tasks for `gpt-oss-120b` and `GLM-5.3-Flash`, write tasks graded from the state through `data/get`, and a dry-run dataset. Published results are in brackets. | Environment | Tools | Served from state (reads / writes) | Retrieval gpt-oss | Retrieval GLM | Writes gpt-oss | Writes GLM | | --- | --- | --- | --- | --- | --- | --- | | Komga | 42 → 46 | 26 / 3 | 12/12 (11/12) | 12/12 (11/12) | 3/4 | 4/4 | | Mealie | 39 → 39 | 36 / 0 | 12/12 (12/12) | 12/12 (12/12) | – | – | | n8n | 30 → 33 | 17 / 1 | 9/9 (9/9) | 9/9 (9/9) | 2/2 | 2/2 | | Sentry | 34 → 34 | 26 / 3 | 12/12 (12/12) | 11/12 (12/12) | 2/4, rerun 0/4 | 4/4 | | Shlink | 17 → 17 | 5 / 0 | 5/7, rerun 7/7 | 7/7 (7/7) | – | – | Every smoke task passed. The misses: - **Sentry writes with gpt-oss:** in every failed episode the model passed `id: "sentry"` for the `/api/0/` segment, which the tool schema describes as `observed: 0`. Every passing episode, and every GLM episode, passed `0`. - **Komga's update and Shlink's first run with gpt-oss:** the provider rejected malformed tool calls (`null` or `undefined` optional arguments). - **Sentry `qa-03` with GLM:** the model never called the alert-rules tool. The first n8n run showed that a digit-free workflow id stayed literal: reading that workflow by id failed because the state held only its list fields. The fixed-length clause fixed that, and the rebuilt n8n reads it correctly. **Live comparison**, seeded by the same scripts: - **Komga 1.29.1:** 9 of 12 steps equal. Collection create, update, delete and the reads after them agree apart from the generated id. Two differences remain: the collection list after a create omits the new collection (recorded membership), and a deleted collection's 404 replays the recorded body. - **n8n 1.123.85:** 3 of 8 steps equal. - n8n refuses to delete a workflow that isn't archived (400); the environment deletes it. - The workflow list replays its recorded response, so deletes don't show in it. - Archiving isn't served. These gaps belong to the write and list serving in #5600 and its base, not to this rule. **User-visible output.** Komga, with the rule: ```json { "name": "patch_collections_by_collection_id", "method": "PATCH", "path_template": "/api/v1/collections/{collection_id}", "api_surface_template": "/api/v1/collections/0RZ576QZQA5KG", "params": [ { "index": 3, "name": "collection_id", "rule": "prefix-variance", "basis": "inferred", "observed_values": ["0RZ576QZQA5KG"] } ], "body_shape": { "type": "object", "properties": { "name": "string", "ordered": "boolean" } }, "statuses": [204], "record_ordinals": [108] } ``` Without the rule the same record is `patch_collections_0rz576qzqa5kg` with `params: []`. **Remaining proof gaps.** The rule is an inference from paths. An app whose identifier-like literal sits beside an opt-in parameter but names a different resource would be templated wrongly. In the 50 captures, every such literal that qualified was the same resource, and every one that didn't qualify was a word. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed Run on macOS with Node v22.23.1 at 33b0643e (the rule, the alias removal, and the fixed-length clause); 9a025b32 adds only the verification record. - `npm run build:cached`, `npm run check:fast`, `npm run format:check`, `npm run scan:todos`, `npm run docs:check`, `npm run verify:test-discovery`, `npm run mcp-catalog:check`: passed. - `npx knip`: passed. - `npm run jscpd`: 3.49% over 3561 files, 3067 clones. Main is 3.49% with 3068. - `npx vitest run --project domain --project services`: 7119 passed, 5 pre-existing skips. - `npm run test:prepare`, then `npm run test:focused --` the analysis-view MCP and CLI boundaries, compact input schema, tool schema validity, and environment serve and export boundaries: 7 files, 76 passed. - `npx vitest run src/domain/analysisView/`: 280 passed. - Main's build and this branch's give identical outputs without the rule: 150 of 150 over the 50 captures, rechecked at 33b0643e. - **Review round (head 6a8beb58):** merged main at 52c84f6f, then fixed the five bot threads in 75af11fd. Shared values stay with the parameter that observed them, each donor's spelling is summarised once, and one observation forms a fixed-length family. Both new tests fail on the previous head. The gates above passed again (domain and services 7255, 5 pre-existing skips; focused boundaries 76; `jscpd` 3.49%), and the tools with and without `prefix-variance` over the 50 captures are unchanged, name for name. - **Review round 2 (head 03b66df9):** bounded the spelling summary for Codex's follow-up: characters are classified in one pass, and a value over 128 characters is compared only exactly. Its test fails on 6a8beb58; the gates passed again (domain and services 7257, focused boundaries 76, `jscpd` 3.49%), and the census over the 50 captures is unchanged. ## Compatibility, safety, and release - Breaking changes or migration steps: none. The rule is opt-in, and outputs without it are unchanged. - Real Hopper/Ghidra, browser, or OS coverage: not applicable. - Package or release metadata impact: none. - Security, privacy, process, or containment review: request lines only; no bodies or headers are read by the rule. ## Author readiness Human owner: <!-- @GitHub-handle --> - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:44:47 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#7021
No description provided.