Skip to content

design: validate a conservative expression declaration policy - #839

Draft
Maya-Kid wants to merge 2 commits into
deeplethe:devfrom
Maya-Kid:codex/stage2-expression-policy
Draft

Maya-Kid wants to merge 2 commits into
deeplethe:devfrom
Maya-Kid:codex/stage2-expression-policy

Conversation

@Maya-Kid

Copy link
Copy Markdown
Contributor

ADR 0032 requires unit/datatype checks for the picker but leaves missing units and explicit dimensionless declarations undefined. This draft proposes a conservative declaration policy and provides an isolated executable editor/policy experiment; it does not tighten production rule writes or enable B2.

Prefer exact known units, missing/ambiguous as unknown, no conversions, same-unit add/subtract and numeric scaling. Decide whether exact 1 denotes explicit unitless and which known declarations belong in the initial allowlist. The report explains the deliberate compatibility change, short FOR SHARE transaction boundary, metadata-only legacy fallback and remaining actual-backend E2E work.

Validation: 10 Node policy tests passed on Linux, a real PostgreSQL lock experiment observed a blocked declaration update until writer commit, and a headless Chromium local picker check passed save/reopen, invalid constants, failed-save retry and protected legacy metadata editing. The browser is a standalone model, not Utopia API E2E. Production APIs, UI and dependencies are unchanged.

The existing ADR status remains unchanged; the appended proposed-revision link points to the exact decisions and reproduction commands. This is a contract-review draft, not a claim that #488 or B2 is complete. The separate API mismatch fix is #838.

Refs #488

… rule writes

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Signed-off-by: dada-yan <BinjunYann@gmail.com>
@WaylandYang

Copy link
Copy Markdown
Contributor

The content here is decision material — it states a policy and asks maintainers to approve it — and the thinking in it is good. My objection is only about where it lives.

docs/decisions/README.md states the purpose of that directory plainly: code records what was built and git records when it changed; neither records why, and that directory does. Putting the reasoning in scripts/prototypes/**/README.md and leaving a five-line pointer in the accepted record splits it. A reader who opens the record in six months finds a stub aimed at a directory whose name says "prototype" — with no number, no row in either index table, no status line for an implementing PR to update, and none of the revision discipline the conventions require. The "Decision requested" section is exactly the thing that is supposed to be numbered and indexed.

Please give this its own numbered record in docs/decisions/, and turn the addition to the accepted record into a dated revision note that names it, per Revisions stay in place.

#832 in this same batch is the pattern to copy: it moved its reasoning into docs/decisions/0048-provenance-references-stay-inside-the-knowledge-base.md, added the row to both index tables, opened an issue for the open design question, and left the migration carrying only what SQL has to say.

One thing that is not my call and that I have flagged for the maintainer: whether the executable prototype itself belongs in the repository. scripts/bench/ is tracked, so there is precedent for committed harnesses, but these add a Python harness and a requirements.txt, and that is a policy question rather than a review point.

Specific to this one: the unit policy table and the FOR SHARE versus FOR KEY SHARE transaction boundary are both answers to open questions 0032 already carries ("Units and datatypes have to be checked when the expression is written, and today nothing checks them"). That makes them a revision of 0032 with a record of their own, not an appendix.

@WaylandYang

Copy link
Copy Markdown
Contributor

Adding one more, on scripts/prototypes/expressions/index.html specifically: the picker experiment should not be a standalone page.

The reason for isolating it is understood and half right — policy.mjs is the proposed policy, not the one in force, and 0032's picker is still an unbuilt cut, so there is nothing in RulesPanel to extend and no case for putting an unapproved policy on a production code path before the decision.

But the isolation costs more than it saves, because of what the page is being asked to answer. 0032's open question is "How deep before the picker loses", with the record's own example being that (revenue − cost) / revenue as nested dropdowns is worse than typing it. That is a question about whether the thing is bearable to use — and this page cannot answer it:

  • It runs on three hardcoded attributes (revenue, cost, ratio). A picker gets bad exactly when a real base puts hundreds of attributes behind each <select>, which is the case the experiment never sees.
  • It makes no API call at all, and "save" stringifies into a <pre>.
  • It reimplements every control with document.createElement, with inline hex colours (#111827, #64748b) and font: 16px system-ui. Living outside web/ also puts it outside pnpm guard, so it would be the one piece of interface in the repository that no style rule reaches — while the shadcn migration and the token bridge are the standing direction for everything else.

So what it demonstrates is the interaction shape in a mock, and the shape was not in doubt. Put it in web/ behind a route or a flag, built from the real components and reading a real base's attributes, and the depth question gets a transferable answer — and nothing has to be thrown away when the real picker lands. As a standalone file its fate is to become a second implementation that rots the day cut B2 ships.

The policy module and its tests are a different matter; policy.mjs being separate from the production validator is fine and is not what this note is about.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants