Skip to content

spec: declare grantedPermissions on EnvironmentArtifactSchema (record of manifest id → PluginPermissions) — the artifact-contract half of #14034 / #11333 Phase 1, which must land BEFORE cloud can write it (plain z.object strips undeclared keys at the artifact door) #14865

Description

@baozhoutao

Filed by the repo:cloud execution seat (seat post #6026, session session_017Wu48ZSjk7HJjyJmGNBtUk, R35) as the framework half that #14034's measurement (comment on that card, 2026-09-03) showed must land first. Triage: domain:* and type are yours — expected domain:spec; Clause-② yes (a new key on a published contract face) ⇒ CONTRACT_REVIEW_TIER. Dedup: no open objectstack card declares a granted-permissions field on the environment artifact (granted across packages/spec/src returns zero permission declarations at pin 655b106c; the requested set is manifest.zod.ts:290-291).

Ruling this executes

#11333 option A (2026-08-30 「同意」) and the #13457 batch ruling (2026-09-01 「同意」): the consented four-class permission set {services, hooks, network, fs} rides the plugin artifact contract; cloud (owner of the install-consent flow) writes it at consent-compile time, objectstack's loader consumes it from the environment-local carrier at materialize time (ADR-0003 / cloud ADR-0007: sys_package_installation is never read on a runtime path).

Measured on cloud 2f469233 × pin 655b106c (details on #14034)

  • The consent flow writes the granted set to exactly one place: sys_package_installation.granted_permissions (cloud routes/package-install.ts:640-652, written :667/:678), preserving absent vs empty (:651-653 emits it only when consent-bearing).
  • The compiled environment artifact envelope (cloud routes/cloud.ts:747-757: schemaVersion, environmentId, commitId, checksum, metadata, functions, manifest, builtAt, builtWith, runtime) does not carry it; the marketplace-install merge loop reads the install row but consumes only enabled / package_version_id / with_sample_data.
  • The env-local carrier (env-artifact-cache.ts:88-102) stores JSON.stringify(artifact) verbatim ⇒ once the envelope carries the key, the carrier carries it for free — the ruling's carrier assumption holds.
  • The consumer at the pin wants a per-plugin map: registerGrantedPermissions(pluginName, PluginPermissions) (packages/core/src/security/plugin-permission-enforcer.ts:102-111), value shape PluginPermissionsSchema (packages/spec/src/kernel/manifest.zod.ts:32-44, .strict()).
  • Pin-lag / silent-stripping: EnvironmentArtifactSchema (packages/spec/src/system/environment-artifact.zod.ts:83) and ManifestSchema (manifest.zod.ts:158) are plain z.object, so an undeclared key written by cloud is stripped at objectstack's artifact door (packages/metadata/src/plugin.ts:900-925, parse at :908/:915). A cloud-first landing would fail silently. ⇒ spec first, pin bump, cloud second.

The ask (spec half)

Declare one top-level envelope key on EnvironmentArtifactSchema:

grantedPermissions: z.record(z.string(), PluginPermissionsSchema).optional()

Coupling

Refs: #14034 · #11333 · #13457 · #13458 · ADR-0003 / cloud ADR-0007 · ADR-0025.

Activity

  1. huangyiirene commented on Sep 3, 2026

    @huangyiirene
    Collaborator

    Triage — sweep repair + graded. pm:queue (kept) · pm:blocking · domain:spec · priority:p1 · needs:contract-review.

    Verified at origin/main — all three load-bearing premises:

    • EnvironmentArtifactSchema is a plain z.object (environment-artifact.zod.ts:83) ⇒ the silent-stripping story is real: a key cloud writes before this lands is dropped at the artifact door, with no error. That is what makes the ordering (spec first, pin bump, cloud second) a correctness requirement rather than a preference.
    • grantedPermissions → 0 occurrences in packages/spec/src. Not yet declared.
    • PluginPermissionsSchema exists at kernel/manifest.zod.ts:33 ⇒ the value shape is available and needs no new type.

    p1: it is the head of a two-deep cross-repo chain — #14034 (repo:cloud) is pm:blocked on this, and #13457 is blocked on #14034 — and the direction is already ruled (#11333 option A, 2026-08-30 「同意」; #13457 batch, 2026-09-01 「同意」). ⛔ Nothing downstream can start until this lands, so grading it below the work it gates would strand both.

    pm:blocking applied as the derived cache for that edge. needs:contract-review on the Clause ② mechanical floor — a new key on a published contract face is always yes; the filer declared it and I am confirming rather than re-deriving.

    Scope — as filed, with three things ⛔ not to negotiate:

    ⚠️ This card is the spec half only. ⛔ Do not write the cloud side, ⛔ do not touch env-artifact-cache.ts (it stores JSON.stringify(artifact) verbatim, so it carries the key for free once declared — the ruling's carrier assumption, and I confirmed the card's reasoning for it stands).

    ✅ Dedup accepted; the zero was paired with a named pin (655b106c) and a positive locator for the requested set.


    Generated by Claude Code

  2. zhuangjianguo commented on Sep 3, 2026

    @zhuangjianguo
    Collaborator

    Claim: PM loop, domain:spec seat (seat post #6017), R1 of this shift
    Session: session_0174WZTU6XcFcS7g2kykC53i (GitHub zhuangjianguo)
    Branch: claude/issue-14865-environment-artifact-granted-permissions
    Worktree: objectstack-issue-14865
    Domain: domain:spec
    File surface: packages/spec/src/system/environment-artifact.zod.ts (one new optional top-level envelope key grantedPermissions: z.record(z.string(), PluginPermissionsSchema).optional() + docblock naming producer and consumer; ⛔ absent vs {} preserved; key = manifest id) · packages/spec/src/system/environment-artifact.test.ts (pins: declared key survives parse; absent and {} round-trip distinctly; an unknown sibling key is still stripped; the manifest-id-vs-package_id residual risk pinned as a stated assumption) · packages/spec/src/kernel/manifest.zod.ts:19-31 (doc-only carrier sentence pointing at the new key; ⛔ no schema change there) · whatever generated artifacts check:generated proves stale (json-schema manifest / references page for the artifact schema) · a liveness-ledger row only if system/environment-artifact is a governed type in packages/spec/liveness/* (the dev measures; a cross-repo producer is written into the note if a row exists) · .changeset/*.md (@objectstack/spec minor — a new authorable/published key). Stop on breach; explain in the report. ⛔ Nothing in packages/metadata, no cloud-side work, no env-artifact-cache.ts.
    Container & model: S/M (the schema line is short; the pins and the ledger question are the work), mode:subagent, model: fable (CONTRACT_REVIEW_TIER). node scripts/pm/dispatch-gates.mjs --tier packages/spec/src/system/environment-artifact.zod.ts packages/spec/src/kernel/manifest.zod.ts at origin/main 9786d39 (15:40Z): "no path-derived mandate: the surface hits none of the 3 declared glob(s)" + "Clause ② SUSPECT surface — a hint, not a verdict" on both paths (packages/spec/src/**); the tier is decided from the card content — a new key on a published contract face is the mechanical floor for clause ②.
    Clause-②: yes
    Serial constraints cleared: open-PR file scan at 15:38Z (22 open PRs, every file list read via REST) — none touches environment-artifact.zod.ts, environment-artifact.test.ts or kernel/manifest.zod.ts; last commit on those files 4d0d9445 (#14714, 2026-09-02T21:14Z) — no same-day churn; lane siblings in flight (#14010 merge round on hook.zod.ts / objectql; #14722 on stack.zod.ts) are file-disjoint; H17 on-hold trigger-file index (#9857, swept 13:47Z) names none of these files. Downstream Blocked-by: edge: #14034 (repo:cloud) waits on this card (the pm:blocking cache); #13457 behind that.

    Decision re-read (all comments read, one — triage 5522848160): rulings in force are #11333 option A (2026-08-30 「同意」) and the #13457 batch ruling (2026-09-01 「同意」), quoted in the card body; triage's three non-negotiables (absent ≠ empty; key on manifest id; ship both pin tests) go into the dispatch as rulings. Premise re-read on origin/main 9786d39 (15:40Z): grantedPermissions → 0 hits under packages/spec/src (positive control: PluginPermissionsSchema → 4 hits in kernel/manifest.zod.ts); EnvironmentArtifactSchema = lazySchema(() => z.object({ at environment-artifact.zod.ts:83 — a plain object, so the silent-strip premise stands. Premise holds.


    Generated by Claude Code

  3. self-assigned this
    on Sep 3, 2026
  4. zhuangjianguo commented on Sep 3, 2026

    @zhuangjianguo
    Collaborator

    Dispatch (R1 of this shift, 2026-09-03T16:05Z) — domain:spec seat, session_0174WZTU6XcFcS7g2kykC53i, seat post #6017. mode:subagent, model: fable (CONTRACT_REVIEW_TIER), size S/M, Clause ② yes. The dev leaves its own Claim: comment below (session + branch + Clause-②: yes + its complete file surface); the assignee stays the PM's.

    Dispatch text handed to the dev, in brief (the two rulings and triage's three non-negotiables are quoted verbatim and marked non-renegotiable; scope = the spec half only):

    • One optional top-level key grantedPermissions: z.record(z.string(), PluginPermissionsSchema).optional() on EnvironmentArtifactSchema, describe naming producer (cloud consent-compile) and consumer (materialize-time loader), absent ≠ {} stated and pinned; key = manifest id, residual risk pinned as the documented assumption.
    • Hypotheses to measure: H1 plain-object strip today / declared-key survival + unknown-sibling strip after (schema-reachable pins); H2 the PluginPermissionsSchema import has no cycle; H3 which generated artifacts move (check:generated --fix, never hand-edited); H4 whether the artifact type is liveness-governed (row only if so, cross-repo scope spelling); H5 the doc-only carrier sentence in manifest.zod.ts; H6 changeset minor.
    • Landing: draft PR with Fixes #14865 + needs:contract-review on the PR in the same stroke (the card already carries it — dual carrier); ⛔ no ready flip. In-seat contract review at tier by this seat on delivery.

    Generated by Claude Code

  5. claude commented on Sep 3, 2026

    @claude
    Contributor

    Claim: os-dev subagent for #14865 (dispatched by the domain:spec seat, seat post #6017, 2026-09-03T16:05Z)
    Session: session_0174WZTU6XcFcS7g2kykC53i (GitHub zhuangjianguo)
    Branch: claude/issue-14865-environment-artifact-granted-permissions (pushed empty at BASE 3386493f)
    Worktree: objectstack-issue-14865
    Clause-②: yes
    Mode: mode:subagent, model: fable (CONTRACT_REVIEW_TIER)

    File surface (complete):

    • packages/spec/src/system/environment-artifact.zod.ts — one new optional top-level envelope key grantedPermissions: z.record(z.string(), PluginPermissionsSchema).optional() with a describe/docblock naming the producer (cloud consent-compile) and the consumer (the materialize-time loader), stating absent vs {}; key = the plugin manifest id.
    • packages/spec/src/system/environment-artifact.test.ts — schema-reachable parse pins: the declared key survives and round-trips; absent stays absent; {} stays {}; an unknown top-level sibling is still stripped (positive control); the value shape is enforced through the strict PluginPermissionsSchema; the manifest-id-vs-package_id residual risk pinned as the documented assumption on the key's meaning.
    • packages/spec/src/kernel/manifest.zod.ts lines 19-31 — a doc-only carrier sentence pointing at the new key; no schema change there.
    • Whatever generated artifacts check:generated --fix proves stale after pnpm --filter @objectstack/spec build (json-schema manifest shard / references page / api-surface if the exported type surface moves) — never hand-edited.
    • .changeset/environment-artifact-granted-permissions.md — @objectstack/spec minor.
    • packages/spec/liveness/* — a row only if system/environment-artifact measures as a liveness-governed type (measured in-run; reported either way).

    Out of scope, not touched: packages/metadata, packages/core, any cloud-side work, env-artifact-cache.ts.

    Premise re-read on origin/main 3386493f (16:10Z): EnvironmentArtifactSchema = lazySchema(() => z.object({ at environment-artifact.zod.ts:83 (a plain object, so the silent-strip premise stands); grantedPermissions 0 hits under packages/spec/src (positive control: PluginPermissionsSchema present at kernel/manifest.zod.ts:33, .strict()); the card body ends with its Refs: line (not truncated); all three comments read (triage 5522848160, PM claim 5528213556, dispatch 5528286028). Premise holds.

    Generated by Claude Code


    Generated by Claude Code

  6. claude commented on Sep 3, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 14865,
      "status": "done",
      "branch": "claude/issue-14865-environment-artifact-granted-permissions",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/14992",
      "head": "84ce33e9 (BASE 3386493f; commits 7b05b01b feat, d4437273 docs regen, 304318e8 pure control test, 84ce33e9 north-star patch round)",
      "premise_still_valid": true,
      "summary": "Declared one optional top-level envelope key, `grantedPermissions: z.record(z.string(), PluginPermissionsSchema).optional()`, on `EnvironmentArtifactSchema`, with a docblock and describe that name the producer (cloud consent-compile, from `sys_package_installation.granted_permissions`) and the consumer (the materialize-time loader via `PluginPermissionEnforcer.registerGrantedPermissions`), state absent (no consent record) vs `{}` (consented to nothing) as never collapsed (no default), key = plugin manifest `id` (not `package_id`) with the residual risk written out, and note the key sits beside `metadata`, outside the checksum digest. 13 schema-reachable parse pins plus one pure sibling-strip control; a doc-only carrier sentence on `PluginPermissionsSchema`; the generated references page regenerated by `check:generated --fix` (the only generated artifact that moved); the seat's patch round added one bullet to `content/docs/concepts/north-star.mdx`; changeset `@objectstack/spec` minor. Premise verified at `origin/main` 3386493f (BASE): plain `z.object` at environment-artifact.zod.ts:83, 0 hits for `grantedPermissions` under packages/spec/src, `PluginPermissionsSchema` strict at kernel/manifest.zod.ts:33, card body ends with its Refs line, all comments read. Hypotheses: H1 holds (ablation in `tests`); H2 no cycle — a static walk of kernel/manifest.zod.ts's 28-file relative-import closure reaches neither system/environment-artifact.zod.ts nor stack.zod.ts, and the built ./system, ./cloud and ./kernel entries (CJS and ESM) load and expose the key; H3 exactly one generated file moved (content/docs/references/system/environment-artifact.mdx, +7) — authorable-surface and its .base.json anchor, json-schema manifest, api-surface, export-origins and declaration-map unchanged (the envelope is lazy, not authorable, adds no export); H4 not liveness-governed (absent from GOVERNED, SPEC_ONLY_SCHEMAS and the metadata-type registry; no ledger file) — no row added, check:liveness green; H5 comment-only, no schema diff in manifest.zod.ts, its describe untouched so the kernel/manifest reference page did not move; H6 minor, changeset gates green (non-breaking, no ADR-0087 marker owed). ENVIRONMENT_ARTIFACT_SCHEMA_VERSION stays 0.1 (additive optional key). Notes for the seat: my REST writes land as `claude[bot]` (App installation token), not the seat's login — the Claim comment is 5528311175 (posted 15:49Z before the first edit); `needs:contract-review` was hung on the PR at creation per the dispatch, before the patch-round message arrived, and no label was written afterwards; dispatch-gates warned STALE TREE (8+ commits behind origin/main at derivation) — no merge of main was done (the PM's open-PR scan read the files as disjoint; the queue rebuilds on main).",
      "tests": "vitest `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/system/environment-artifact.test.ts` on 304318e8 (the last commit touching tests or source; 84ce33e9 is one .mdx): `Tests 27 passed (27)` = 14 pre-existing + 13 new. `pnpm --filter @objectstack/spec typecheck` on 304318e8: `tsc --noEmit`, check:scripts-typecheck and `check:test-typecheck: OK` all green; `tsc -p tsconfig.test.json --listFiles` lists src/system/environment-artifact.test.ts (1 hit) and 0 errors mention the edited files. Reverse verification, fix committed first, source-resolved (the test imports ./environment-artifact.zod relatively and packages/spec/vitest.config.ts declares no alias — no build in either leg, dist untouched throughout): Leg A restored the BASE schema file with `git checkout BASE -- PATH` (on disk: grep -c grantedPermissions = 0, hash-object equals the BASE blob 6ae63da0) — `11 failed | 16 passed (27)`, the 11 being every pin that needs the key, the 16 = 14 pre-existing + the pure control + absent-stays-absent; Leg B injected `.passthrough()` with perl (on disk: 1 match, hash 0ce2c7a1 differs from the HEAD blob 09ce094c) — `2 failed | 25 passed (27)`, exactly the two sibling-strip controls; restore via `git checkout HEAD -- PATH` (absolute path, trap on EXIT INT TERM) proven after each leg by hash-object == HEAD blob 09ce094c and `git diff HEAD -- PATH` empty (porcelain 0 lines); control leg on unmodified HEAD `27 passed (27)`. Direction observed = direction predicted for both legs. The rebuilt dist on 304318e8 carries `grantedPermissions: z.ZodOptional...` in dist/environment-artifact.zod-*.d.ts (fresh declarations, not a cache). eslint --no-inline-config on the 3 edited TS files: exit 0 (a scoped reading, not the repo-wide run).",
      "gates": "Derived on the actual diff, no paths (`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`; first derivation at 7b05b01b gave 58 commands, the re-derivation after the docs-regen commit gave 76 — the 18 docs families were run as a delta and `--ran` on the final list reads `76 derived, 76 run, 0 UNRUN`; every exit code captured before any pipe, one log per gate). On 304318e8: 71 green by their own verdict lines, among them `check:generated` after the rebuild `All 15 generated artifacts are up to date`, check:api-surface, check:authorable-surface, check:docs, check:export-origins, check:dual-source-exports, check:exported-any, check:liveness, check:strictness-ledger, check:skill-examples (`256 prose examples type-check across 3 surface(s)` after building the client-react closure), check:changeset-no-major, check:empty-changeset, check:adr-0087-registration, check:nul-bytes, check:cross-package-test-inputs, check:test-source-alias, check:type-check-coverage. NOT MEASURED, each by its own PREREQUISITE NOT MET / not-built text (none a finding): check-test-completeness (grades a saved turbo test log), check-dev-prereqs (66 of 67 packages have no dist — whole workspace not built), check:dual-build-cjs-loads and check:type-check-debt (need the built workspace closure). Patch round on 84ce33e9: the 34 families dispatch-gates derives for content/docs/concepts/north-star.mdx (all already in the union) re-run — 33 green including check:doc-anchors, check:doc-authoring, check:docs-single-h1, check:nul-bytes, check:docs, check:doc-frontmatter, check:section-landing-index, and lint check:doc-formula-expressions / check:doc-security-posture (measured green now that the lint closure exists); check-test-completeness NOT MEASURED. CI status at report time: in_progress (not polled).",
      "deviations": "(1) Whole-tree gates needing the built workspace (check-dev-prereqs, check:dual-build-cjs-loads, check:type-check-debt) and the test-log grader (check-test-completeness) NOT MEASURED locally — CI's run; scoped equivalent for the one package this diff touches: the built ./system, ./cloud and ./kernel entries load in CJS and ESM and expose the key. (2) Downstream consumer typecheck beyond @objectstack/spec NOT MEASURED locally (the prefix direction `...@objectstack/spec` is the whole repo): the change is an additive optional key on an inferred type — widening only — and the two named consumer sites (packages/metadata/src/plugin.ts spread-parse; packages/core's `PluginPermissions as GrantedPermissions` alias) reference no envelope key by name; the required TypeScript Type Check job covers it. (3) Repo-wide `pnpm lint` not run (CI's); the 3 edited TS files were linted, reported as a scoped reading, not as a narrowed measurement. (4) vitest/typecheck not re-run on 84ce33e9: that commit changes one .mdx no test or tsc program reads. (5) Five dist-reading spec gates went red once on a re-run because dist's mtime was older than src after the test commit and the ablation checkouts; rebuilt on 304318e8, all green — completeness, not a finding. (6) PR body PATCHed once to record the patch-round head (the platform normalises the session footer to bare on edit; attribution lives in the body prose). (7) `check-half-states` ran twice as derived (371 s and 380 s, 100+ REST reads each) — see findings.",
      "files_changed": [
        "packages/spec/src/system/environment-artifact.zod.ts (+63): import PluginPermissionsSchema; the key with docblock + describe; header Boundary bullet",
        "packages/spec/src/system/environment-artifact.test.ts (+146): 13 pins + 1 pure control under `grantedPermissions — install-time granted set per plugin manifest id (#14865)`",
        "packages/spec/src/kernel/manifest.zod.ts (+8): doc-only carrier sentence on PluginPermissionsSchema; no schema change",
        "content/docs/references/system/environment-artifact.mdx (+7): regenerated by check:generated --fix, never hand-edited",
        "content/docs/concepts/north-star.mdx (+4): one bullet in the Environment Artifact contents list (seat's patch round)",
        ".changeset/environment-artifact-granted-permissions.md (+47): @objectstack/spec minor"
      ],
      "mcp_calls": "0 — no mcp__github__* call was made; the card body and all comments were read via the repo-scoped REST endpoints (probe GET /repos/.../issues/14865 answered 200 at 16:08Z — channel open for this session), the Claim comment, PR creation, the one label add and this report went via REST POST/PATCH, everything else via git.",
      "open_questions": [
        {
          "question": "`grantedPermissions` sits beside `metadata`, so it is outside the `checksum` digest (documented as the digest of the canonical `metadata` serialization only). Is integrity over the granted set wanted on the envelope? Informational for the contract review; not blocking.",
          "options": [
            "A — no change: consent state is control-plane state re-emitted per assembly, consistent with the ruling's carrier reading; the fact is documented on the key, in the header Boundary bullet and on north-star",
            "B — a separate later decision: widen the digest or add a second digest over the granted set; not this key"
          ],
          "recommendation": "A, because the ruling places the set on the envelope as a carrier and the checksum contract as written is over `metadata`; changing digest semantics is its own contract decision with its own consumer (the loader's checksum verification) and belongs to no card in this chain."
        }
      ],
      "out_of_scope_findings": [
        "NOT FILED — handed to PM for filing (PM tooling; the dedupe channel was deliberately not spent): scripts/pm/dispatch-gates.mjs names scripts/pm/check-half-states.mjs in its `declared WHOLE-TREE and named on every card` set; it is a report-only board patrol (its own footer: `Report-only: findings are patrol input, not a gate verdict`) that took 371 s and 380 s and 100+ REST reads per run here, so every dev card that runs the derived family pays it with no verdict to read. Suggest excluding report-only patrols from the per-card family or marking them PM-only.",
        "Observation, not filed: the built ./cloud and ./system entries carry separate runtime copies of the envelope schema (tsup.config.ts `splitting: false`, per-entry self-contained bundling, `#8133 stays on hold` in that file) — cross-entry runtime identity was never a property of dist, and the declaration-level single source (#4740 pin) holds. Pre-existing, unchanged here."
      ]
    }

    Generated by Claude Code


    Generated by Claude Code

  7. zhuangjianguo commented on Sep 3, 2026

    @zhuangjianguo
    Collaborator

    Contract review — PASS (in-seat, at tier) · ACCEPT — PR #14992 (head 84ce33e9, Fixes #14865). domain:spec seat, session_0174WZTU6XcFcS7g2kykC53i (seat post #6017), 2026-09-03T16:58Z. Fuse: last_served_model = claude-fable-5-1 = CONTRACT_REVIEW_TIER (read 15:29Z). Provenance: the 2026-08-31 ruling (in-seat contract review by the dispatching lane).

    Report: os-dev-report 5529148343 (status: done, premise_still_valid: true; source/test readings on 304318e8, the docs patch round on 84ce33e9 — the final head differs from the tested head by one .mdx only, verified by this seat: git diff 304318e8..84ce33e9 = content/docs/concepts/north-star.mdx +4). Dev claim 5528311175 (15:49Z, Clause-②: yes; posted as claude[bot], the App-token identity — the branch is the identity, per the claim rules). Reviewed against the card, triage 5522848160, the full diff on GitHub and this seat's readings of origin/main.

    ① Derived judgments (Clause ② yes — a new key on a published contract face): the accept set widens by exactly one optional top-level key on EnvironmentArtifactSchema, grantedPermissions: z.record(z.string(), PluginPermissionsSchema).optional(); the value is the strict PluginPermissionsSchema by identity (pinned: record.valueType is the same object; an unknown permission class is refused with unrecognized_keys at grantedPermissions.PLUGIN); an unknown top-level sibling is still stripped (two controls, one with no grantedPermissions present at all); absent ≠ {} is carried by the schema — no .default({}), both readings round-trip and stay distinguishable on the parsed value; key = manifest id, with the residual risk (a package_id-shaped key parses and is never looked up) documented on the key and pinned on its description text. Emitted shape: an artifact without the key parses exactly as before (the 14 pre-existing pins unchanged); ENVIRONMENT_ARTIFACT_SCHEMA_VERSION stays 0.1 — additive and optional, correct. Public surface: no new export (api-surface, export-origins, declaration-map unchanged; the envelope is not in the authorable surface); the only generated artifact that moves is the reference page (check:generated 15/15 after --fix). Ruling fidelity — #11333 option A / #13457 batch (carrier declared on the envelope; cloud writes at consent-compile; the loader consumes at materialize) — met; triage's three non-negotiables (absent ≠ empty; manifest id; both pin tests shipped) — met.
    ② Semver / changeset: @objectstack/spec minor — correct for a new published key; check:changeset-no-major, check:empty-changeset and check:adr-0087-registration green (non-breaking, no marker owed).
    ③ Boundary flags: (a) grantedPermissions sits beside metadata, outside the checksum digest — the dev's open question, answered A (no change here: the ruling places the set on the envelope as a carrier and the digest contract as written covers metadata); the gap is filed for triage as #14993 (a security-boundary question is the maintainer's, not this PR's); (b) per-entry runtime copies of the envelope in dist (splitting: false) — pre-existing, #8133 on hold; (c) check-half-states inside the per-card gate family (371 s / 380 s and 100+ REST reads per run) — already filed as #14899 by an earlier dev, not re-filed.

    Checklist: draft; Fixes #14865 on line 1 (the spec half completes the card; #14034 / #13457 are named without closing keywords and stay open); scope = the claimed files plus the seat's patch-round bullet in north-star.mdx (the drift bot named the page; this seat verified it enumerates the envelope's contents and now lists the key); no content/docs/releases/; NOT governed (0 of 6 paths on the final file list); trial merge of 84ce33e9 vs origin/main 77a532d6 clean; tests 27/27 (14 + 13) on 304318e8; typecheck with --listFiles proof (1 hit); reverse verification both legs measured with on-disk proof (Leg A: BASE schema restored ⇒ 11 red; Leg B: .passthrough() injected ⇒ exactly the two sibling-strip controls red; restores proven by the HEAD blob hash and an empty git diff HEAD); gate family 76 derived / 76 run — 71 green, 5 NOT MEASURED (whole-workspace prerequisites, CI's); the 34 docs families re-run green on the patch round. Declared and accepted: downstream consumer typecheck beyond @objectstack/spec NOT MEASURED locally (an additive optional key on an inferred type — widening only; the TypeScript Type Check job on 84ce33e9 is the reading and must be green before the flip); repo-wide lint is CI's; mcp_calls: 0 — the dev read and wrote through repo-scoped REST (claim, PR creation, one label add, one body PATCH, the report), recorded, not faulted.

    Landing shape: NOT governed, Clause ② PASS ⇒ ordinary queue landing. Same stroke: needs:contract-review cleared on both carriers (PR #14992 + this card), each read back. Ready flip + auto-merge (squash) follow once every check on 84ce33e9 is green (this seat's checkpoint). On MERGED: the card closes via Fixes, pm:dispatched is stripped, origin/main probed for the key. For the repo:cloud seat: #14034's unlock criterion is an installable @objectstack/spec release carrying the key plus cloud's pin bump — not this merge (cross-repo rule); its own unlock scan reads it from there.


    Generated by Claude Code

  8. zhuangjianguo commented on Sep 3, 2026

    @zhuangjianguo
    Collaborator

    Enqueue reading — domain:spec seat, 2026-09-03T17:24Z: PR #14992 marked ready 17:22Z, auto-merge (squash) armed 17:22:54Z (provenance 14992#issuecomment-5529474740), added_to_merge_queue 17:24Z. On MERGED: the card closes via Fixes, pm:dispatched is stripped, origin/main probed for grantedPermissions; #14034 (repo:cloud) waits on an installable @objectstack/spec release carrying the key plus its pin bump.


    Generated by Claude Code

  9. zhuangjianguo commented on Sep 3, 2026

    @zhuangjianguo
    Collaborator

    Landing note (PM seat domain:spec, session_0174WZTU6XcFcS7g2kykC53i, 2026-09-03T18:17Z) — PR #14992 merged through the queue at 17:59:29Z as e58ea8b3 (queued 17:24Z); this card closed via Fixes at 17:59:30Z.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions