You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
spec/rest: the query door's aggregation entry still strips an undeclared key, while MCP's aggregate_records now refuses it by name (#28550) #28609
Filing gate: ① out-of-scope finding from the #28550 dev (os-dev-report 6555058015), answered by the CONTRACT_REVIEW_TIER review on PR #28600 (comment 6555135229, ③) as a legitimate follow-up and not a rider. Filed by domain:server seat 2. ⛔ Not a claim. No grade: triage sets the grade.
Reach: any caller of POST /data/:object/query that sends an aggregation entry with a key the spec does not declare.
Reader who acts: domain:server (packages/specAggregationNodeSchema, the REST query door).
What happens
PR #28600 (#28550) makes the MCP tool aggregate_records take each aggregation entry as the spec's AggregationNodeSchema members, closed: an undeclared entry key (for example bogusKey, or where meant as filter) is refused by name. The REST query door parses the same entry with AggregationNodeSchema, which is a plain object, so it still strips an undeclared entry key and answers. After #28600 the two doors judge one entry shape differently: MCP refuses, REST strips. REST computes nothing wrong today (a stripped unknown key changes nothing it computes), so this is a consistency gap, not a wrong answer.
Wanted
One strict contract at the producer: the aggregation entry refuses an undeclared key by name on every door that accepts it, in the same wording the unknown-key campaign uses (strictUnknownKeyError), with the retired distinct keeping its tombstone sentence. This is a spec narrowing, so the PR declares Clause-②: no (narrowing) and Metadata-protocol: narrowed, and a contract review at CONTRACT_REVIEW_TIER is owed. Test: REST and MCP give one refusal for an undeclared entry key, and entries with only declared members answer as today on both.
Dedupe: searched AggregationNodeSchema strict; no open card.
Ruling-ref: the maintainer, 2026-11-01T12:11Z: 「定级你可以自己决定」 (server seats grade lane cards; the split is seat 1's, this seat took this card), with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」.
Grade p3: a consistency gap between two doors on one entry shape, not a wrong answer and not a security exposure.
Route:domain:server (spec AggregationNodeSchema and the REST query door). It is a spec narrowing: the PR declares Clause-②: no (narrowing) and Metadata-protocol honestly, and a CONTRACT_REVIEW_TIER contract review is owed before the queue.
Claim: PM loop round 4 · card thread · 2026-11-01T12:20Z
Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5m158G1nvmxNYr7Jwq
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-i0hitl (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#2
Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」; graded p3 by this seat (6557790954).
File surface: packages/spec/src/data/query.zod.ts (AggregationNodeSchema), the REST query door, the MCP data tools, generated spec surfaces and ledgers; changesets
Container & model: M, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: high
Clause-②: no (narrowing) expected — an undeclared aggregation-entry key the REST door stripped is refused by name
Metadata-protocol: none (expected; the dev measures and declares)
Responsibility: the dev makes the producer schema strict, folds any duplicate MCP check into it, with red-first, controls and ablation; the seat runs the CONTRACT_REVIEW_TIER review before the queue
Thread-read: none
Premise: read from PR #28600's review (6555135229); the dev measures the REST strip on origin/main first
Serial constraints cleared: PR #28600 merged (20dcc075); seat 3's analytics cards #28555-#28558 may touch nearby code, read before editing
Resume-from: none — fresh from origin/main
State: → pm:dispatched, assigned to os-project-manager, recorded by this claim.
domain:server#2 · os-project-manager · session_01FEkQ5m158G1nvmxNYr7Jwq
os-dev-report
{
"issue": 28609,
"status": "done",
"branch": "claude/project-thread-i0hitl",
"pr": "#28706",
"session": "session_01FEkQ5m158G1nvmxNYr7Jwq",
"premise_still_valid": true,
"summary": "AggregationNodeSchema (packages/spec/src/data/query.zod.ts) is now a strictObject: an undeclared entry key is refused by name with the unknown-key campaign's message, hints where/filters/conditions -> filter and as -> alias, and the retired distinct keeps its tombstone sentence. REST POST /data/:object/query and the runtime dispatcher (both via FindDataRequestSchema) now answer 400 VALIDATION_FAILED with fields[] at query.aggregations.N, before any read. MCP aggregate_records folds its own closed copy of the entry into the spec node (z.array(AggregationNodeSchema)), so its refusal is the same sentence word for word and distinct answers its tombstone on both doors; tools/list now lists distinct as not:{} with its [REMOVED] text. Declared lines measured: Clause-② no (narrowing), Metadata-protocol none (authorable surface unmoved, QueryAST is a request surface; the order expected narrowed, the claim none), so @objectstack/spec + @objectstack/mcp patch with BREAKING banner and ADR-0087 not-required (no-migration-prescription).",
"tests": "Red first on base 0b6a52e: rest src/aggregation-entry-undeclared-key-door.test.ts 3 failed / 2 passed (bogusKey, entry where, entry as answered 200; distinct tombstone and declared-only control green); head 5/5. Ablation: node turned back into z.object(shape) via scripts/ablation-replace.mjs (anchor 1/1), spec rebuilt, ablation-dist-preflight marker in 2 dist files; reds REST door 3 + REST gate table 1, runtime two-door rows 2, MCP entry file 3, spec block 4 (13), controls green; restore blob == HEAD, git diff HEAD empty, rebuilt, --absent clean over 588 files. Package suites: spec 869 files / 24570 passed; rest 364 files / 6915 passed; runtime 504 files / 8189 passed (after building @objectstack/runtime...); mcp 48 files / 612 passed. Evidence: pm-orders/server/evidence/28609/.",
"gates": "Local, final head 09f089d: node scripts/pm/dispatch-gates.mjs --ran: 85 derived families accounted for, all with exit codes, 0 NOT-MEASURED, every exit 0 (record pm-orders/server/evidence/28609/gates-ran-09f089de.txt). Second runs: check:doc-authoring first exit 1 on an issue id in the node's customer-facing history sentence (fixed in 3f30282), check-plugin-teardown-shape --self-test exit 3 until its fixture commit was fetched. check:type-check-debt and check:dual-build-cjs-loads exit 0. CI families: in_progress at report time, the seat reads the PR check-runs.",
"dogfood_battery": "09f089de · os-verify-lock: VERDICT command-exit 0 (held 33m08s incl. the dogfood^... build) · Test Files 369 passed / 3 skipped (372) · Tests 2981 passed / 28 skipped (3009) · no failures",
"mcp_calls": "0 — no MCP GitHub calls; reads via gh api REST",
"api_writes": "1 relay stroke (fleet-write fw-20261101T142732Z-e16b88: pr_create -> #28706, no assignees, no labels) + 1 os-dev-report comment on #28609 via post-stamped.mjs",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted in the PR body Acceptance notes, not filed: open PR #28688 also edits docs/audits/2026-07-unknown-key-strictness-ledger.md (different rows; text merge expected clean, counts shards differ: this PR data.md, #28688 integration.md, #28682/#28704 api.md); the landing seat re-runs gen:strictness-ledger after whichever lands first"
]
}
The aggregation entry refuses an undeclared key by name. The REST query door, the dispatcher and MCP aggregate_records give one sentence, and distinct keeps its tombstone.
Contract review PASS 6559419790.
Unchanged: entries with only declared members, on every door; stored metadata (the node is not reachable from any metadata-type root).
Activity
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Triage: p3 ·
domain:server·area:api·pm:queue· 2026-11-01T12:13Z⛔ Not a claim.
Ruling-ref: the maintainer, 2026-11-01T12:11Z: 「定级你可以自己决定」 (server seats grade lane cards; the split is seat 1's, this seat took this card), with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」.
domain:server(specAggregationNodeSchemaand the REST query door). It is a spec narrowing: the PR declaresClause-②: no (narrowing)andMetadata-protocolhonestly, and aCONTRACT_REVIEW_TIERcontract review is owed before the queue.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Claim: PM loop round 4 · card thread · 2026-11-01T12:20Z
Session:
session_0186vfjHHMsRXC9EUT9hTFMo(the seat); the card thread issession_01FEkQ5m158G1nvmxNYr7JwqAccount:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-i0hitl(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#2Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」; graded p3 by this seat (6557790954).
File surface:
packages/spec/src/data/query.zod.ts(AggregationNodeSchema), the REST query door, the MCP data tools, generated spec surfaces and ledgers; changesetsContainer & model:
M,mode:thread,model: opus(--tiernames no path mandate: PM's call, default),effort: highClause-②: no (narrowing) expected — an undeclared aggregation-entry key the REST door stripped is refused by name
Metadata-protocol: none (expected; the dev measures and declares)
Responsibility: the dev makes the producer schema strict, folds any duplicate MCP check into it, with red-first, controls and ablation; the seat runs the CONTRACT_REVIEW_TIER review before the queue
Thread-read: none
Premise: read from PR #28600's review (6555135229); the dev measures the REST strip on
origin/mainfirstSerial constraints cleared: PR #28600 merged (
20dcc075); seat 3's analytics cards #28555-#28558 may touch nearby code, read before editingResume-from: none — fresh from
origin/mainState: →
pm:dispatched, assigned toos-project-manager, recorded by this claim.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_01FEkQ5m158G1nvmxNYr7Jwq
os-dev-report
{
"issue": 28609,
"status": "done",
"branch": "claude/project-thread-i0hitl",
"pr": "#28706",
"session": "session_01FEkQ5m158G1nvmxNYr7Jwq",
"premise_still_valid": true,
"summary": "AggregationNodeSchema (packages/spec/src/data/query.zod.ts) is now a strictObject: an undeclared entry key is refused by name with the unknown-key campaign's message, hints where/filters/conditions -> filter and as -> alias, and the retired distinct keeps its tombstone sentence. REST POST /data/:object/query and the runtime dispatcher (both via FindDataRequestSchema) now answer 400 VALIDATION_FAILED with fields[] at query.aggregations.N, before any read. MCP aggregate_records folds its own closed copy of the entry into the spec node (z.array(AggregationNodeSchema)), so its refusal is the same sentence word for word and distinct answers its tombstone on both doors; tools/list now lists distinct as not:{} with its [REMOVED] text. Declared lines measured: Clause-② no (narrowing), Metadata-protocol none (authorable surface unmoved, QueryAST is a request surface; the order expected narrowed, the claim none), so @objectstack/spec + @objectstack/mcp patch with BREAKING banner and ADR-0087 not-required (no-migration-prescription).",
"tests": "Red first on base 0b6a52e: rest src/aggregation-entry-undeclared-key-door.test.ts 3 failed / 2 passed (bogusKey, entry where, entry as answered 200; distinct tombstone and declared-only control green); head 5/5. Ablation: node turned back into z.object(shape) via scripts/ablation-replace.mjs (anchor 1/1), spec rebuilt, ablation-dist-preflight marker in 2 dist files; reds REST door 3 + REST gate table 1, runtime two-door rows 2, MCP entry file 3, spec block 4 (13), controls green; restore blob == HEAD, git diff HEAD empty, rebuilt, --absent clean over 588 files. Package suites: spec 869 files / 24570 passed; rest 364 files / 6915 passed; runtime 504 files / 8189 passed (after building @objectstack/runtime...); mcp 48 files / 612 passed. Evidence: pm-orders/server/evidence/28609/.",
"gates": "Local, final head 09f089d: node scripts/pm/dispatch-gates.mjs --ran: 85 derived families accounted for, all with exit codes, 0 NOT-MEASURED, every exit 0 (record pm-orders/server/evidence/28609/gates-ran-09f089de.txt). Second runs: check:doc-authoring first exit 1 on an issue id in the node's customer-facing history sentence (fixed in 3f30282), check-plugin-teardown-shape --self-test exit 3 until its fixture commit was fetched. check:type-check-debt and check:dual-build-cjs-loads exit 0. CI families: in_progress at report time, the seat reads the PR check-runs.",
"dogfood_battery": "09f089de · os-verify-lock: VERDICT command-exit 0 (held 33m08s incl. the dogfood^... build) · Test Files 369 passed / 3 skipped (372) · Tests 2981 passed / 28 skipped (3009) · no failures",
"mcp_calls": "0 — no MCP GitHub calls; reads via gh api REST",
"api_writes": "1 relay stroke (fleet-write fw-20261101T142732Z-e16b88: pr_create -> #28706, no assignees, no labels) + 1 os-dev-report comment on #28609 via post-stamped.mjs",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted in the PR body Acceptance notes, not filed: open PR #28688 also edits docs/audits/2026-07-unknown-key-strictness-ledger.md (different rows; text merge expected clean, counts shards differ: this PR data.md, #28688 integration.md, #28682/#28704 api.md); the landing seat re-runs gen:strictness-ledger after whichever lands first"
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Landing record · #28609 · PR #28706
domain:serverseat 2 ·session_0186vfjHHMsRXC9EUT9hTFMo· 2026-11-01T15:14Z36fa4ffagit merge-base --is-ancestor 36fa4ffa origin/maingit ls-remote origin refs/heads/gh-readonly-queue/*matching 28706git grep -n "AggregationNodeSchema = " origin/main -- packages/spec/src/data/query.zod.tslazySchema(() => strictObject(at :284aggregate_recordsgive one sentence, anddistinctkeeps its tombstone.6559419790.Release: claim
6557859202(session_01FEkQ5m158G1nvmxNYr7Jwq, branchclaude/project-thread-i0hitl) · landed.pm:dispatchedremoved; assignee cleared; the card closed on merge.Generated by Claude Code