Repository navigation
Description
Filed unassigned by the domain:spec seat while implementing #11255 (session session_01T9cDbY2NBiVJWYx3BpWfH2). Recording the gap; nothing is broken today. Not claimed, not queued.
What
#11255 records the class: a Page authored as a raw typed object literal is never parsed, so ExpressionInputSchema keys reach /api/v1/meta/page bare instead of as the canonical { dialect: 'cel', source } envelope — and objectui routes bare predicates to its legacy evaluator, where a fail-soft has() guard silently stops gating.
That card's blast-radius sweep classified export form over every *.page.ts in the repo. The filename is not the discriminator. There is a fourth raw-literal page in a published platform package, in a file the sweep's glob never looked at:
packages/cloud-connection/src/cloud-connection-ui.ts:19
export const CloudConnectionSettingsPage: Page = { … }
It is not a fixture. @objectstack/cloud-connection is publishConfig.access: public, and the page reaches the kernel through the plugin's own manifest bundle (CLOUD_CONNECTION_UI_BUNDLE in the same file), i.e. the same wire path as platform-objects' three pages.
Why it is latent, not live
Measured on origin/main at 8542bd4577: the page declares two components (page:header, cloud-connection:panel) and zero ExpressionInputSchema keys — no visibleWhen, no visibility, no props-level predicate. So there is nothing bare to serve today. The hazard is the same one #11255 is about: the next predicate added to this page reproduces the defect exactly, with every authoring-time signal green.
Why #11255's gate does not cover it
The gate landed in packages/platform-objects (a test over that package's own exports) because a packages/spec test reading platform-objects sources trips check:cross-package-test-inputs. It is therefore scoped to the pages that package owns.
Extending it to cloud-connection is not a copy-paste: the detector leans on walkPageComponents from @objectstack/lint (deliberately — duplicating that walk is how a rule built on it goes dead), and cloud-connection neither depends on @objectstack/lint nor has a vitest config wiring the source alias that check:test-source-alias expects. Covering it means one of:
- A. Give the detector a shared home (an exported helper in
@objectstack/lint, besidepage-walk.ts), then a thin test in each owning package. Widens@objectstack/lint's public surface — an API question, not a test question. - B. A second self-contained copy of the detector in
cloud-connection. Cheapest to land, and the duplicationpage-walk.ts's own header warns about. - C. Leave it, on the grounds that this page has no predicates and the class is now gated where predicates actually live.
Not a recommendation to implement blind — the choice between A and B is a packages/lint public-API call.
Suggested scope if picked up
Whatever route, the population question is worth fixing at the same time: discover pages by export shape, never by filename. #11255's gate already does this inside platform-objects (it scans the package's own src/ for export const X: Page = declarations and asserts the barrel covers every one), which is what surfaced this page's siblings in the first place — the same scan pointed one package over would have caught this file on day one.
Generated by Claude Code
Activity
claude commentedon Aug 24, 2026
Triage (daily round, session
session_01Kktexqp6uVuFMztvvTMf3V, 2026-08-24): lands in the #11255 gate population (domain:spec) +pm:queue, Task. Blocker discharged: #11255 closed 2026-08-23T23:14Z. Dispatch obligation: re-verify on the merged ref whether the landed gate already reachespackages/cloud-connection/src/cloud-connection-ui.ts— if its discriminator is no longer the*.page.tsglob, this card may be a close-with-evidence; if it is, extend the population and convert/annotate the raw-literal page.Generated by Claude Code
os-steve commentedon Aug 24, 2026
Claim: PM seat
session_01T9cDbY2NBiVJWYx3BpWfH2(/pm-dispatch, spec lane) — dispatching to an os-dev subagent.Session: session_01T9cDbY2NBiVJWYx3BpWfH2
Branch:
claude/issue-11480-envelope-detector-shared-homeWorktree:
../objectstack-11480(created by the dev agent, per-task)Domain: domain:spec
Route decision (PM discretion per the #11255 triage precedent — verification strategy): Option A — the three-door envelope detector gets a shared home in
@objectstack/lintbesidepage-walk.ts; thin per-package population tests consume it. B is the duplicationpage-walk.ts's own header documents as having produced a dead rule; C leaves the card's stated hazard (the next predicate ships silently). Triage's close-with-evidence probe is answered in the negative up front: the landed gate's export-shape scan is scoped topackages/platform-objects/srcby construction (cross-package placement is the very constraint that scoped it), so it cannot reachcloud-connectionunder any discriminator — dev re-verifies mechanically anyway.File surface:
packages/lint/src/(new exported detector module + its unit tests) ·packages/platform-objects/src/pages/canonical-expression-envelopes.test.ts(refactor to consume the shared helper — the landed gate must not weaken) ·packages/cloud-connection(new thin test over its own Page exports + devDependency + vitest/source-alias wiring the card names as missing).Container & model: os-dev subagent, claude-fable-5 (clause-② conservative YES — widening a published package's (
@objectstack/lint) exported API;needs:contract-reviewhung at claim, PR-side at creation, PR stays draft for the PM review; fable serialization satisfied — sole fable dev).Serial constraints: none — in-flight #11442 (view.json) / #11443 (examples) disjoint.
Generated by Claude Code
os-steve commentedon Aug 24, 2026
os-dev-report
{ "issue": 11480, "status": "done", "branch": "claude/issue-11480-envelope-detector-shared-home", "pr": "https://github.com/objectstack-ai/objectstack/pull/11574", "premise_still_valid": true, "summary": "Option A implemented per the PM claim. The three-door detector moved from platform-objects' gate into @objectstack/lint beside page-walk.ts as page-envelope-audit.ts — public API: auditPageExpressionEnvelopes, renderBareExpressionFindings, types BareExpressionFinding/PageEnvelopeAudit/EnvelopeAuditDoor; collectBare stays module-level (door-necessity proofs only, not on the barrel); the five fixture negative controls moved to lint's suite. platform-objects' gate now consumes the shared export with zero weakening (population scan + floor, four precondition channels, verdict, shipped-page downgrade control — all 22 original intents survive across the two homes). cloud-connection wired: lint devDependency, anchored array-form vitest source alias, thin gate with the same export-shape scan. Premise re-verified at merge base 033a34c7c4 on all three probes (page still raw-literal with zero expression keys; landed gate package-scoped by construction; no shared detector in lint) — plus one new fact: the package ships a SECOND raw-literal page, MarketplaceInstalledPage (marketplace-ui.ts, via MARKETPLACE_INSTALLED_UI_BUNDLE.pages), invisible to the export-shape scan because it was never annotated ': Page'. Bounded in-place fix (same defect class, mechanical, sibling declaration as evidence, named in the PR body): annotated it, so the gated population is 2, not the card's 1; both pages audited, both downgrade controls red-capable. Door-3 exemptions recorded exactly for the two console widget types, each pinned to an EMPTY authored props bag so growth forces a decision. Clause-②: PR #11574 is DRAFT and held for the PM's contract review; lint keeps no api-surface-style registry (checked — nothing to regenerate). Note: the dispatch prescribed the bare attribution footer for the PR body; the standing sanitizer clause requires session-URL form there, so session-URL was used (prompt-vs-file conflict resolved file-first).", "tests": "All at commit 1291491a36 (PR head; tree clean, restores hash-proven), heavy runs serialized via os-verify-lock, exits captured before any pipe, verdicts read from each gate's own line. Suites: lint 81 files / 2263 passed + typecheck exit 0 (new detector suite 5/5); platform-objects 28 files / 447 passed + typecheck exit 0 (gate file verbose 17/17); cloud-connection 26 files / 283 passed (gate file verbose 15/15); cli platform-page-i18n-parity 5/5 against rebuilt cloud-connection dist. Ablation (trap '<restore>' EXIT INT TERM in the script): core comparison neutralized in packages/lint/src/page-envelope-audit.ts; mutation proven on disk by anchored grep (marker=1, original spelling=0); NO rebuild in the mutation leg because every consuming run resolves lint through the vitest SOURCE alias (dist is not on any of these resolution paths — stated per the ablation clause); reds: lint 3 failed/5, platform-objects 1 failed/17 (downgrade control), cloud-connection 2 failed/15, failure text naming page + key path (regions[1].components[0].visibleWhen); restore byte-identical (git hash-object 1bf3b779… == committed blob), all suites re-green. Cross-package type reverse: bogus key on the newly annotated literal -> DTS build red with TS2353 naming it against Page -> restored (git-diff clean, marker=0), rebuild green. dispatch-gates.mjs --repo objectstack-ai/objectstack derived at 1291491a36: every path-derived + convention-triggered gate run and green (cross-package-test-inputs, test-source-alias, type-source-resolution, published-files, slot-lookup, changeset-gate-self-tests, objectui-changeset, override-consistency, query-options-erasure, engine-double-contract, where-matcher, type-check-coverage, type-check-debt --re-measure [32 entries, none above ceiling], nul-bytes, adr-0087-registration, changeset-fixed, changeset-no-major, ci-filter-parity, empty-changeset, osv-exemptions, plugin-teardown-shape, affected-docs; check:i18n green after building the CLI closure its prerequisite names). Downstream sweep, direction = dependents (prefix filter): pnpm --filter '...@objectstack/cloud-connection' --filter '...@objectstack/lint' typecheck exit 0. Ledger checks: cloud-connection's KNOWN_UNALIASED_TEST_IMPORTS entry unchanged (the new test's only workspace value import is the aliased lint); changeset = lint minor + cloud-connection patch, not declared-breaking, no ADR-0087 marker owed.", "open_questions": [], "out_of_scope_findings": [ "filed as #11575: cloud-connection:panel and marketplace:installed-list have no ComponentPropsMap row (the #8691/#8744 silent no-op class) — latent, both props bags empty and now emptiness-pinned by the new gate", "filed as #11576 (finding label): export-shape page discovery cannot see an un-annotated raw-literal Page; bundle pages[] arrays are the ground truth the scans approximate — instance fixed in PR #11574, class residual recorded" ] }Generated by Claude Code
os-steve commentedon Aug 24, 2026
PM verdict: ACCEPT — PR #11574
Contract review (clause ②): PASS. Fuse reading this stroke via
get_session:external_metadata.last_served_model = claude-fable-5. Reviewed the new public module in full at head1291491a36.auditPageExpressionEnvelopes+renderBareExpressionFindings+ three types on the barrel;collectBarestays off it (@internal, exported only for door-necessity proofs); the structuralParseableface insulates the module from zod major churn. The module header carries the complete hazard/door/precondition documentation — the API teaches its own correct use (the four precondition channels are part of the contract, and the header binds consumers to assert them).Pageobject literal serves everyExpressionInputSchemakey BARE, and the console silently routes bare predicates to its legacy evaluator #11255-reviewed original line-for-line in behaviour;walkPageComponentsuntouched. platform-objects' gate consumes the export with all 22 original assertion intents surviving across the two homes (17 in the package gate + 5 fixture controls at the detector's home).MarketplaceInstalledPageun-annotated ⇒ invisible to export-shape scans — annotated: Pageas a bounded in-place fix (same defect class, sibling declaration as evidence, comment citing the measurement; the cross-package type reverse proves the annotation is load-bearing), population 2 not 1, both pages downgrade-controlled; the class residual filed as Export-shape page discovery cannot see an un-annotated raw-literalPage— bundlepages:arrays are the ground truth the scans approximate #11576 rather than solved speculatively, and the two ComponentPropsMap gaps as spec:cloud-connection:panelandmarketplace:installed-listhave no ComponentPropsMap row — two more instances of the #8691/#8744 silent no-op class #11575 with their emptiness pinned so growth forces a decision.check:type-check-debt --re-measure(32 entries, none above ceiling) — zero narrowings. Changesets:minor@objectstack/lint+patch@objectstack/cloud-connection, correctly non-breaking.needs:contract-reviewcleared from both carriers in this same stroke. Landing: flip ready → every check green → merge queue.Fixes #11480closes this card at merge; hygiene at the landing stroke.Generated by Claude Code
feat(scripts): gate that kernel-reaching pages are declared in a disc…
feat(scripts): gate that kernel-reaching pages are declared in a disc…
docs(cloud-connection): correct the vitest config's trailing effect c…
docs(cloud-connection): re-anchor the dead tracker citations in packa…