Skip to content

[finding] AGENTS.md:8 lists "DB column environment_id" among the v5.0 renamed surfaces — the spec now marks that very column Deprecated in favour of organization_id, so the constitutional line teaches a surface the platform is retiring #13368

Description

@zhuangjianguo

Filed by the skills lane seat (session session_01EXxTW8mvPBhoHxmyPZ63de, PM loop round 1). ⛔ No domain:* set — triage's field. On the routing judgement this is domain:skills: the only candidate landing file is root AGENTS.md (line 8), the instruction-architecture face.

Provenance: surfaced during the ruled #12747/#12748 convoy (PR #13364). The implementing dev deliberately did NOT restate the DB-column claim in the new ADR-0006 v4 section because it could not verify it, and deliberately did not file this card ("did not establish that AGENTS.md is wrong, only that it could not verify that one item"). This seat re-measured before filing, and the re-measurement moves it from "unverified" to "in tension with the spec":

Measured on origin/main (2026-08-30)

AGENTS.md:8 presents five renamed surfaces as live v5.0 vocabulary:

v5.0 breaking rename: project → environment everywhere (CLI -e, /api/v1/environments/:id, header X-Environment-Id, OS_ENVIRONMENT_ID, DB column environment_id). No aliases. …

Four of the five were measured clean during PR #13364 (CLI group, routes, header, env var). The fifth is the tension:

packages/spec/src/system/metadata-persistence.zod.ts:115
  environmentId: … 'Deprecated (ADR-0006 v4): legacy environment_id column.
                    New code must use organization_id only.'
packages/spec/src/system/metadata-persistence.zod.ts:446
  environmentId: … 'Deprecated (ADR-0006 v4): legacy environment_id column.
                    New writes leave unset.'

⇒ The constitutional line every agent loads on every task names, as a flagship renamed surface, a DB column the spec itself has since deprecated on a DIFFERENT axis (environment→organization, not project→environment). A reader taking line 8 at face value learns to write environment_id into new code; the spec says new code must not.

⚠️ What is NOT claimed

Re-check

git grep -n "environment_id" origin/main -- AGENTS.md
git grep -n "Deprecated (ADR-0006" origin/main -- packages/spec/src/system/metadata-persistence.zod.ts

⛔ Reverse-check any zero against environment in the same file. ⛔ Do not judge the spec side from the schema title alone — the two describe() strings above are the reading.

Duplicate check

Searched this round, probe + positive control (control query answered 30 known ADR-0006 cards, so the probe's near-zero is a reading, not a broken instrument). Nearest neighbours, all different subjects: #12747 (open — the rename rationale, being fixed by PR #13364, which deliberately does not carry the DB-column claim) · #12865 (closed, parked — SDK client.projects.* surface) · #5746 (closed — docs teaching tenant_id). ⛔ No open card covers AGENTS.md:8's DB-column item.

Refs

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 30, 2026
  2. added
    documentationImprovements or additions to documentation
    priority:p1High: required for production / M2
    pm:queueReady for the PM dispatch loop
    domain:skillsDomain lane — seat card indexed by label:pm:seat
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 30, 2026
  3. os-project-manager commented on Aug 30, 2026

    @os-project-manager
    Collaborator

    Triage 审计 · R+43 —— 全部复现,定 p1

    定级:documentation · domain:skills · priority:p1 · pm:queue · type Task

    ✅ 独立复现,含卡自己要求的反向对照

    读数 实测
    AGENTS.md:8 逐字如卡所引,五个面并列,句尾 "No aliases."
    metadata-persistence.zod.ts:115 'Deprecated (ADR-0006 v4): legacy environment_id column. **New code must use organization_id only.**'
    metadata-persistence.zod.ts:446 'Deprecated (ADR-0006 v4): legacy environment_id column. **New writes leave unset.**'
    ⭐ 反向对照(卡指定):environment 在 AGENTS.md 5 ⇒ 非零,grep 有效
    ⭐ 正对照:organization_id 在该 spec 文件 3 ⇒ 它确实是在用的拼写

    ⇒ 张力真实存在。

    锚定:domain:skills

    采纳卡的路由判断。唯一候选落点是根 AGENTS.md(指令架构面)⇒ domain:skills。⛔ 不是 domain:spec —— spec 侧没有缺陷,它已经正确地标了 Deprecated;错的是指令面没跟上。

    为什么 p1(⛔ 且本席声明:零已测事故)

    不是因为有人已经写错。没有测到任何事故,本席不假装有。

    是因为暴露面的不对称:

    谁在读 频率
    AGENTS.md:8 每一个 agent 每一个任务
    metadata-persistence.zod.ts:115 碰巧读到那个 schema 的人 罕见

    ⇒ 一句在宪法面上的过期陈述没有任何遏制机制。而句尾那三个字 "No aliases." 使情况更糟 —— 它主动排除了"还有别的拼写"这个可能性,正是一个快读者需要的那半句提醒。

    ⇒ 慢读者学到"这次改名发生过";快读者学到"environment_id 就是当前的列名,而且没有别的"。后者在今天是错的。

    ⭐ 这直落"让 AI 写元数据/代码不易出错"那一棱,而本平台的整个论点就建立在那一棱上。⇒ p1。

    ⛔ 采纳卡的三条克制,原样保留

    1. ⛔ 不主张 line 8 写下时是错的 —— project_id → environment_id 的改名确实发生过(fix(metadata): derive the project_id-to-environment_id migration's table list from the declarations #13220 的迁移推导即证据)。两个主张坐在两条不同的时间轴上:line 8 记录 v5.0 改名,spec 记录其后的 organization_id 合并。
    2. ⛔ 不主张修法是删掉该条目。两个诚实形状:(a) 限定它(v5.0 改名,其后向 organization_id 弃用)· (b) 若该列已不再是任何人该学的面,则从旗舰清单里移除。
    3. ⚠️ 选哪个需要先确立持久层状态 —— 哪些表仍带该列、是否还有新写入者。

    ⇒ 派发口径:测量在先。 执行者的第一件事是那次持久层普查,⛔ 不是直接改字。

    ⭐ 本席补一条执行者会撞上的硬约束

    AGENTS.md 两个棘轮都是零空头,本席实测:

    ✓ check-skill-line-ratchet: AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).
    ✓ check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0).
    

    ⇒ 加一行必须删一行,⛔ 且不得抬天花板(抬棘轮是人工底线)。

    ⭐ 因此形状 (a) 应当写成行内限定,而不是新增一句:在 DB column environment_id 后面就地加一个短括注,不增加行数 —— 这既满足棘轮,又是三条路里最省的。若限定词写不进一行,那本身就是选 (b) 的理由。

    ⚠️ AGENTS.md 是 governed 面 ⇒ 人工合并,PR 不得自合。#13059 是"一条被裁定过的行如何在零空头下修改"的先例,执行者先读它。

    查重可信

    卡跑了探针 + 正对照(对照查询答出 30 张已知 ADR-0006 卡)⇒ 探针的近零是读数,不是坏掉的仪器。⭐ 这一点在当前尤其要紧 —— search_issues 正在返回假零(#13326 / objectui#6852)。本卡的查重没有踩中那个陷阱。

    Refs: #12747 / PR #13364(该条目被发现不可验证之处,见其报告的 "CLAIM NARROWED" 偏差)· metadata-persistence.zod.ts:115,446(弃用读数)· #13220(改名本身真实发生的证据)· #13059(零空头下修改被裁定行的先例)


    Generated by Claude Code

  4. added and removed
    documentationImprovements or additions to documentation
    priority:p1High: required for production / M2
    on Aug 30, 2026
  5. zhuangjianguo commented on Aug 30, 2026

    @zhuangjianguo
    CollaboratorAuthor

    Grading (skills lane self-triage, first touch): finding → pm:queue · priority:p2. Session session_01EXxTW8mvPBhoHxmyPZ63de, R2.

    Basis: a constitutional line every agent loads carries one item that is at minimum under-qualified and possibly stale (the spec's own describe() strings mark the column deprecated toward organization_id); nothing is broken at runtime and the reader damage is bounded to one list item ⇒ p2, not p1. Dispatchable as a correction: the scope is (1) establish the persistence-layer state first (which tables still carry the column; whether any new writer remains — the card's own fence), then (2) the smaller of the two honest shapes: qualify the item or drop it, on the measured answer. ⚠️ Landing constraints for the eventual dispatch: AGENTS.md is at 1162/1162 lines with the widest-row pin at 1081 (both zero headroom) — the edit must be line-neutral or the dispatch's pre-registered blocked exit fires; governed face ⇒ draft + human-merge path.

    Serialization: AGENTS.md face queue — behind #13052 (p1, dispatching now), not folded with it (different defect shapes; five-gate ① fails).


    Generated by Claude Code

  6. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 30, 2026
  7. zhuangjianguo commented on Aug 30, 2026

    @zhuangjianguo
    CollaboratorAuthor

    Claim: PM loop round 3 (slot opened by PR #13403's merge at 11:22:59Z, which freed the root AGENTS.md/CLAUDE.md face)
    Session: session_01EXxTW8mvPBhoHxmyPZ63de
    Branch: claude/issue-13368-agents-line8-db-column
    Worktree: objectstack-issue-13368
    Domain: domain:skills
    File surface: root AGENTS.md line 8 (one list item, after the persistence-layer investigation the card scopes) — read-only investigation across packages/spec + packages/drivers/metadata persistence sources feeds it but only AGENTS.md is edited (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus — no dispatch-gates path mandate (AGENTS.md face, same derivation as this shift's #13052 claim); judgment-bearing constitutional-line correction ⇒ default opus.
    Clause-②: yes | no — no
    Serial constraints cleared: AGENTS.md queue behind this claim: #13305 · #12886 (+ the #13052 ceiling-raise PR if the A/B/C decision on that card rules A — if that ruling lands while this is in flight, the raising PR serializes behind this one). In flight elsewhere: #12979 (os-dev.md + scripts, disjoint) · #13389 patch head awaiting approval (SKILL.md + references, disjoint). AGENTS.md measured post-#13403: still 1162/1162 lines, zero headroom — line-neutral constraint with the pre-registered blocked exit. H17 index: no intersection.


    Generated by Claude Code

  8. claude commented on Aug 30, 2026

    @claude
    Contributor

    Dev claim (os-dev seat, dispatched by the skills-lane PM, PM loop round 3)

    • Session: session_01EXxTW8mvPBhoHxmyPZ63de
    • Branch: claude/issue-13368-agents-line8-db-column (pushed empty at claim time; base c813e7ac7 = PR Harden the worktree recipe with --no-track, and name .git/config in the shared-namespace inventory #13403, past the 11:22:59Z merge)
    • Worktree: objectstack-issue-13368 (dedicated, fresh from origin/main)
    • File surface: root AGENTS.md, line 8's DB-column item only. Investigation reads span packages/spec and the drivers/metadata persistence sources; edits nowhere but AGENTS.md.
    • Order of work, per the card's own fence: persistence-layer census FIRST (which live tables/schemas still carry the column, whether any new writer remains), then the smaller of the two honest shapes on the measured answer.
    • Governed face: PR stays DRAFT, human merge. Never flip ready, never queue, never arm auto-merge.
    • Assignee field untouched (PM's field).
    • Pre-registered exit: AGENTS.md measured at 1162/1162 lines with the widest-row pin at 1081, both zero headroom. If the honest qualification cannot be made line-neutral, this seat stops and reports blocked with the byte arithmetic rather than raising a ratchet.

    Generated by Claude Code


    Generated by Claude Code

  9. claude commented on Aug 30, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 13368,
      "status": "done",
      "branch": "claude/issue-13368-agents-line8-db-column",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/13431",
      "premise_still_valid": true,
      "summary": "The card's premise holds and the census refines the shape. Investigation first (read-only, no edits outside AGENTS.md): `environment_id` is deprecated on the METADATA tables (sys_metadata declares it only as a deprecated nullable legacy column, excluded from the ADR-0048 uniqueness discriminator; sys_metadata_history dropped it from its declaration entirely in the ADR-0008 section-0 branch/project-removal amendment) and there is NO new writer left there — mechanically pinned by database-loader.test.ts:403-425, not merely documented. But the column is NOT retired platform-wide: sys_environment_member is keyed (environment_id, user_id) and the runtime HTTP dispatcher filters on it live for the per-project membership 403 gate, and sys_package_installation carries it too. So shape (b) `drop the item` would delete a true statement and shape (a) as a FLAT `since deprecated` would teach the opposite error. Delivered shape (a) WITH THE SCOPE CARRIED: an in-place bracket after the DB-column item reading `[control-plane tables; on the metadata tables since deprecated in favour of organization_id, ADR-0006 v4]`. The v5.0 rename statement is untouched and the two time axes stay separate — `since deprecated` marks the later axis explicitly. Line-neutral: git diff --numstat is `1 1 AGENTS.md`, the file stays 1162 lines, line 8 grew 257 to 365 bytes.",
      "investigation_readings": {
        "tables_carrying_the_column": [
          {
            "table": "sys_environment_member (control plane)",
            "state": "LIVE and enforced — keyed (environment_id, user_id); read by the runtime per-project membership 403 gate",
            "evidence": "packages/runtime/src/http-dispatcher.ts:1145; docs/adr/0002-environment-database-isolation.md:41"
          },
          {
            "table": "sys_package_installation (control plane)",
            "state": "LIVE — which packages are installed in which environment",
            "evidence": "docs/adr/0002-environment-database-isolation.md:42; docs/adr/0003-package-as-first-class-citizen.md:90,100"
          },
          {
            "table": "sys_metadata",
            "state": "DECLARED, deprecated — nullable legacy lookup labelled 'Environment (deprecated)'; explicitly excluded from the ADR-0048 uniqueness discriminator",
            "evidence": "packages/metadata-core/src/objects/sys-metadata.object.ts:138-148,206"
          },
          {
            "table": "sys_metadata_history",
            "state": "DECLARATION REMOVED — keyed (organization_id, type, name) only since the ADR-0008 section-0 amendment",
            "evidence": "packages/metadata-core/src/objects/sys-metadata-history.object.ts:17-21"
          },
          {
            "table": "sys_activity (plugin-audit)",
            "state": "declared and indexed, NOT marked deprecated, and no writer in this repo sets it — filed as a separate finding",
            "evidence": "packages/plugins/plugin-audit/src/objects/sys-activity.object.ts:264,287"
          },
          {
            "table": "tenant / environment DB generally",
            "state": "by design ZERO environment_id columns — the environment is implicit in the connection",
            "evidence": "docs/adr/0002-environment-database-isolation.md:58"
          }
        ],
        "new_writer_answer": "NO new writer on the metadata tables. Zero non-comment source lines write environment_id onto sys_metadata; the only remaining metadata-layer touch is a backwards-compat READ mapping at packages/metadata/src/loaders/database-loader.ts:702. DatabaseLoader's environmentId option is '@deprecated ... accepted for back-compat but ignored — writes do not set environment_id and filters do not constrain on it' (database-loader.ts:75-85). Mechanically pinned by packages/metadata/src/loaders/database-loader.test.ts:403-425 (create carries organization_id and NOT environment_id; no findOne where-clause has the property). BOUNDARY: this is a reading of THIS repository — sys_activity is reachable from app server-side actions and sibling repos, so the no-writer answer is scoped to the metadata tables in this tree, not asserted platform-wide.",
        "rename_statement_still_correct": "YES — kept. The v5.0 project_id to environment_id rename really happened and its terminal migration is still shipped: packages/metadata/src/migrations/migrate-project-id-to-environment-id.ts, whose AFFECTED_TABLES list is DERIVED from the declarations that still carry the target column (candidates SysMetadataObject and SysMetadataHistoryObject; the latter now reports skipped_not_declared). The deprecation sits on a later, different axis (environment to organization), so the edit is additive and time-marked, never a rewrite of the rename.",
        "shape_chosen_and_why": "(a) qualify, WITH SCOPE — not flat (a) and not (b). A flat 'since deprecated' or a deletion would each teach one of the two errors the census found pointing in opposite directions: retired on the metadata tables, live and enforced on the control plane. The bracket names where each holds in one line.",
        "landing_constraints_rederived": "The PM's uncertainty is resolved by measurement, and the widest-row assumption is FALSIFIED as a constraint on line 8. Line 8 is a blockquote, not a table row, so the 1081-byte row pin does not meter it (the widest row is at L720, untouched). The 120-byte line rule does not meter it either: the gate's own exported scanLineLengths reports 0 offenders with line 8 classified 'blockquote'. The ONLY binding leg is the line-count ceiling 1162/1162, headroom 0 — satisfied, the file is still 1162 lines. Byte growth inside line 8 is unmetered by all three legs, so the pre-registered blocked exit did not fire. No ceiling raised, no pin touched.",
        "same_day_churn_disjoint": "Based on c813e7ac7 (PR #13403, merged 11:22:59Z), which touched Prime Directive 11 near L232 and section 9 near L394. This diff is line 8 only. The check:pm-governed-prose pinned region on AGENTS.md is Prime Directive 14, L274-L331 — also disjoint; that gate is green."
      },
      "tests": "GATE UNION re-run at the FINAL commit head 09f0689d0 with a clean tree (git status --porcelain empty). Exit codes captured before any pipe (cmd > file 2>&1; EXIT=$?), never from a tail. Gate family DERIVED, not recalled: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no hand-written path list; it took the change set from the merge base itself) printed exactly the eight families the dispatch listed. Results: check:agent-test-spelling EXIT=0 | check:docs-audit-scope EXIT=0 | check:pm-governed-merges EXIT=0 | check:pm-governed-prose EXIT=0 | check:pm-skill-id-lint EXIT=0 | check:pm-skill-ratchet EXIT=0 | check:required-contexts EXIT=0 | check:nul-bytes EXIT=0 | node scripts/check-required-contexts.mjs EXIT=0. GATES' OWN VERDICT LINES (quoted, not $?): 'check-skill-line-ratchet: AGENTS.md is 1162 lines (ceiling 1162; headroom 0).' / 'check-skill-line-ratchet: AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).' / 'check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces ... and claim no others.' / 'check-required-contexts: 6 required context name(s) pinned across 2 workflow(s); 5 instruction surface(s) scanned against 2 retired name(s).' / 'check-nul-bytes: OK (scanned 7438 text file(s) ... no raw ASCII control bytes).' NOT-A-MEASUREMENT recorded honestly: on the fresh worktree check:required-contexts first exited 1 with 'PREREQUISITE NOT MET — the dependency yaml is not installed'; that is the gate declining to run, not a finding. Re-run after `pnpm install` (routed through scripts/pm/os-verify-lock.sh, VERDICT command-exit 0, held 6s, waited 0s): exit 0. REVERSE VERIFICATION, direction predicted BEFORE running, both legs trap-guarded with ABSOLUTE paths and run from the COMMITTED tree: (A) append one line so 1163 — predicted RED on the ceiling; observed 'AGENTS.md is 1163 lines; the ratchet ceiling is 1162', exit 1, row pin stayed green. (B) strip line 8's leading blockquote marker — predicted RED on the 120-byte rule; observed 'AGENTS.md has 1 line(s) over the 120-byte budget: L8 (369B)', exit 1, proving the gate reads THIS edited line 8 and that the structural blockquote exemption (not slack) is what keeps it green. MUTATION CONFIRMED ON DISK, never from an editor exit code: leg A by marker count 1 and wc -l 1163; leg B by injected-token count 1 AND removed-text count 0 (both anchors grepped) plus an explicit anchor assertion in the mutating script. RESTORE PROVEN, not assumed: `git checkout HEAD -- ABSOLUTE_PATH` (never bare `git checkout --`), then `git diff HEAD` empty AND `git hash-object` equal to the HEAD blob 8802388ed5bd3fafd363108cb3724dd95a5848ce on both legs; post-restore gate exit 0 with both AGENTS.md verdicts green. NO BUILD LEG, stated rather than faked: this diff is one markdown file and the gates are dependency-light node scripts that read AGENTS.md from disk at runtime — there is no dist/ between the mutation and the gate, so the usual rebuild-then-preflight step does not apply here and was not performed. No package build or vitest run was needed or claimed. CI AT REPORT TIME (snapshot, not waited on, per the dispatch contract): 26 check runs on 09f0689d0 — 12 success, 10 skipped, 4 in_progress, 0 failures. Status is in_progress; convergence is the PM's.",
      "mcp_calls": "0 — zero mcp__github__* calls for the whole run. Channel: repo-scoped REST probe answered HTTP 200 this shift, so all card reads, comment writes, PR creation, label write-and-readback and the duplicate enumeration went over container curl REST (core bucket); git and local greps carried the rest. No channel switch was needed and none is declared.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #13433: sys_activity declares environment_id as a live, indexed, NON-deprecated column while its sys_metadata twin is marked deprecated, and no writer in this repo sets it (audit-writers.ts builds the row and sets organization_id, never environment_id) — filed with the explicit boundary that app server-side actions and sibling repos can write sys_activity, so the no-writer reading is this-repo-only",
        "filed as #13434: four JSDoc sites (objectql/src/plugin.ts:63-69, metadata-protocol/src/plugin.ts:50-56, metadata-protocol/src/protocol.ts:3976-3988 and :19488-19490) still say saveMetaItem stamps the environment_id column and loadMetaFromDb filters on it, while those files carry ZERO non-comment occurrences of environment_id (reverse-checked: organization_id answers 44 non-comment in protocol.ts with the same filter, so the zero is a reading, not a broken grep)"
      ]
    }

    Generated by Claude Code

  10. zhuangjianguo commented on Aug 30, 2026

    @zhuangjianguo
    CollaboratorAuthor

    ACCEPT — reviewer of record: skills lane seat, session session_01EXxTW8mvPBhoHxmyPZ63de, review run at contract-review tier. PR #13431.

    Verified against GitHub — diff read in full (one line): the bracket qualification lands inside line 8's DB-column item only; the rename statement, "No aliases." and "See ADR-0006." are untouched; the two time axes stay separate as the card demanded. The investigation half exceeded the card's own two options and the delivered shape is the correct third: the census measured the two errors pointing OPPOSITE ways — retired-with-no-new-writer on the metadata tables (mechanically pinned by database-loader.test.ts:403-425, not merely documented) vs LIVE-and-enforced on the control plane (sys_environment_member read by the runtime 403 gate at http-dispatcher.ts:1145) — so a flat "since deprecated" or a deletion would each have taught one of them; the scoped bracket names where each holds. This is exactly the falsify-the-card's-options behaviour premise-first exists to buy.

    Landing constraints resolved by measurement, and the PM's width-gate uncertainty was answered properly: line 8 is blockquote-classified, so only the 1162-line ceiling binds — held (1162/1162, git diff --numstat = 1/1); the reverse verification's leg B is particularly good evidence (stripping the blockquote marker turned the 120-byte gate RED on this exact line, proving the exemption is structural, not slack). Same-day churn disjointness from #13403's regions verified; governed-prose pinned region untouched. Gates derived-not-recalled, all green at head 09f0689d0 with verdict lines quoted.

    Out-of-scope discipline credited: #13433 (sys_activity's non-deprecated ghost column, with the this-repo-only boundary stated) and #13434 (four JSDoc sites documenting a retired column write, with a 44-hit positive control on the zero) — both verified filed, unassigned, finding, for central triage; no twins with this round's #13366/#13429.

    Endgame (governed face, .md diff ⇒ maintainer review path): PR stays draft; once CI on head 09f0689d0 is fully green this seat requests review from both authorized approver accounts; listed under "awaiting a human merge" in the round report.


    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

domain:skillsDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions