- the unknown runtime schema path error now states that canonical paths
contain dots and must be a single argument while space-separated tokens
resolve as a CLI path; help text and docs only reach agents that consult
them, the error is the one surface guaranteed to be seen at failure time
- the app trust diagnostic comment is shortened to the durable constraint
(do not pin absolute Catalog-size counts) instead of narrating the change
- NewDeliveryToolSearchEngine's doc comment notes the memo serves long-lived
hosts; the shipped schema search command rebuilds per invocation through
NewDeliveryToolSearchEngineWithConfig
The diagnostic test pinned absolute counts from one Catalog generation:
1123 intent cases, Recall@5 == 990/1123, 1098 tools and the 402/721
language slices. Merging main grew the Catalog to 1121 tools, so the
population became 1147/407/740 and the test failed as a size drift
rather than as a trust regression.
- the absolute counts are removed; the observed intent, language-slice
and context values are logged for CI forensics and the headline numbers
stay in the generated comparison JSON
- identity coverage is still enforced exhaustively, but the expected
count is derived from report.Context.ToolCount instead of a literal
- the trust contract that does not move with Catalog size stays a hard
gate: every identity pass rate == 1, alias cases non-zero, all four
integrity counters == 0, zero-result rate == 0, non-empty language
slices and ReductionVsFullSchema >= 0.99
- SearchSubqueries returned a nil candidate slice on the
decomposed_exact_filtered refusal, so that one strategy encoded
"candidates":null while every other path encoded []; the refusal now
carries an empty slice and a marshal assertion pins the wire shape
- the memoized delivery engine was never invalidated: it indexes one
Catalog generation and caches its source/surface hashes, but
RegisterSchemaSourceRoot -> resetDeliverySchemaCatalogState left the
memo installed, so a re-registered root could be served stale hashes.
Catalog delivery reset now clears it, with a ForTest wrapper and a
regression test for the rebuild
- dangerous filter Unicode is rejected before the effect vocabulary and
Catalog product checks, so a control/Bidi character returns
dangerous_filter_unicode instead of being echoed back through
invalid_effect; the filter list is an ordered slice, not a map, so the
reported field name is deterministic
- dws schema help and RFC 5.8 record the path-form boundary: multi-token
args resolve as a CLI path, a canonical path must stay one argument
- --explain and ToolSearchScoreBreakdown declare that the reported score
is the raw value while ordering uses the quantized key
- --limit/--candidate-limit help state that 0 means "use the default",
which was already the behavior but read as an asymmetry against the
rejected negative values
- bootstrap seeds become named constants and are published in both
evaluation reports (bootstrap_samples/bootstrap_seed/
recovery_bootstrap_seed) so an interval is reproducible without
reading the source
- dingtalk-shared documents the cross-product summary --dry-run flag and
that its command list is a plan, not business data
The RFC, source-implementation research, GitHub architecture research,
ranking evaluation report, 2026-08-14 optimization plan and ten-round
review record were six separate files that cross-linked each other for
the same decision chain. They are merged into
docs/tool-search-progressive-discovery.md as Part 1..6, ordered
decision -> research -> evidence -> plan -> review record.
- cross-file links become in-document "本文档 Part N" pointers; the five
remaining relative links (source and evaluator paths) still resolve
- section content is unchanged apart from one addition: 5.8 Inspect now
records the path-form boundary (multi-token args resolve as a CLI path;
a canonical path must be passed as a single argument), matching the
dws schema help text
typedJSONValue marshaled a typed value and then routed the result through
rawJSONValue, which runs json.Valid before decoding. On that path the input is
whatever json.Marshal has just produced, so the validation scan can only ever
succeed: it re-read every marshaled document for nothing.
The decode step is now shared by both entry points. rawJSONValue keeps its
json.Valid check, because it still accepts untrusted input, while typedJSONValue
decodes what it marshaled directly. Across the 1121-tool set this removes about a
third of the Schema Catalog projection work: the internal/app schema suite goes
from 26.0s to 17.2s uninstrumented, and from 291.1s to 241.0s under -race.
The delivered Catalog is byte-for-byte unchanged. check-generated-drift,
check-schema-catalog and check-schema-binary each regenerate the same
source_hash sha256:93b8d44eb163bd2898c78397d22af92d378e3dc4e20f56b33277b51e4342e2e6,
and the two error contracts are preserved: typedJSONValue still rejects a value
json.Marshal cannot encode, and rawJSONValue still rejects invalid JSON.
The five internal/app partitions ran end to end inside one job, so the app
shard's wall clock was the sum of all five: 780s in CI, of which the schema
partition owned 357s. Each partition is now its own matrix shard, so they run
concurrently and the shard's wall clock is set by its slowest partition rather
than by their total. Every partition shard still selects the same single
internal/app package, so the impacted-package query maps the shard name back to
app and the partition only chooses which tests run.
The helper gains a partition argument and a list-partitions mode. APP_PARTITIONS
is the single source of truth for the set, and the discovery pass still runs in
every job, so each one independently verifies that the partition patterns cover
every top-level test exactly once before running the one it was asked for.
Two fail-closed checks guard the split, because the helper's own coverage check
can no longer prove the whole package ran once the partitions are separate jobs:
- The helper cross-checks APP_PARTITIONS against the coverage counters in both
directions, so a counted partition that nothing dispatches and a dispatchable
partition with no counter both fail instead of silently skipping tests.
- TestCIAppRacePartitionMatrixMatchesHelper pins the workflow's app-<partition>
shards to list-partitions output in both directions, so a partition cannot
lose its job while every job stays green.
The discovery loop variable is renamed from partition to spec: it would
otherwise shadow the partition requested on the command line, which run mode
reads after the discovery pass completes.
The schema partition's 52 tests assert structural Schema-to-Cobra contracts over
a single goroutine: none of them call t.Parallel or start a goroutine, so the
race detector has no concurrent access to observe there. The process-global lazy
metadata that does need race coverage (schema_source_root's atomic.Value, the
parameter-binding lazy loaders) is exercised by internal/cli's concurrent tests,
which stay instrumented.
The instrumentation was not free here. The partition shares a single sync.Once
Catalog build whose work is allocation-heavy, and -race made it roughly 11x
slower: 26s -> 291s locally, and 357s of the app shard's 780s in CI. Within that
partition TestFinalSchemaToolsHaveExecutableBaseCommands alone accounted for
262s, not because the test is expensive but because it is the first caller to pay
for the shared snapshot; its 1121 subtests together measure 0.00s.
run_partition now takes the instrumentation mode explicitly and fails closed on
an unrecognized value, so a typo cannot silently drop -race from a partition that
is supposed to carry it.