Skip to content

fix: repair CLI lifecycle and confirmed data, Studio, and runtime bugs - #300

Merged
thsnkhn merged 6 commits into
mainfrom
codex/release-audit
Oct 2, 2026
Merged

thsnkhn merged 6 commits into
mainfrom
codex/release-audit

Conversation

@thsnkhn

@thsnkhn thsnkhn commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

This patch repairs install/update failure handling, gives long CLI operations visible progress, and fixes confirmed Record, Studio, import and worker bugs found during the release audit. Issues and reproductions were recorded before implementation.

  • Installers require a successful version probe, preserve the active binary on failure, reject directory destinations, and stop cleanly on POSIX signals. Native Windows/macOS CI now upgrades an actual v0.0.6 installation; Windows also exercises downgrade and locked-file recovery.
  • CLI operations use delayed stderr progress with plain CI/piped output, unchanged stdout and clear prompts. App cloning inherits the caller's cancellation context.
  • Record name collisions recover through savepoints; update/delete hooks lock their current snapshot before validation and mutation.
  • Studio can create defaults-only Records, clear optional typed values, preserve explicit nulls and upload attachments on saved Single settings.
  • CSV import bookkeeping uses Core's scoped system writer while target writes retain the current actor's permissions; PostgreSQL counts are decoded correctly. Worker database failures use bounded handler cleanup.
  • Linux CI and release jobs now run PostgreSQL regressions. Installation/release/CLI docs describe tested behavior without adding a self-update command.

Validation on Linux: 1,236 Go tests with PostgreSQL 17 and no individual skips; go vet; focused CLI/data/import/worker race checks; 110 Studio tests; production and embedded Studio builds; Chromium form smoke with mocked API; installer recovery/signal tests; all six release archives and checksums built; Linux archive smoke passed. Actual published v0.0.6 installed, generated/tidied/built a project, prepared PostgreSQL and served health plus Studio assets. Native-host CI and the final published-release upgrade smoke are required before release completion.

Fixes #287
Fixes #288
Fixes #289
Fixes #290
Fixes #292
Fixes #293
Fixes #294
Fixes #295

Refs #273 (installer-based lifecycle subset; discovery/uninstall design remains open).

Deferred with reproductions and acceptance: #143 (interrupted import idempotency), #291 (required attachment creation), #296/#297 (permission-scoped update/fetch semantics), #298 (Git transport descendants), #299 (cancellation while waiting for confirmation). No permission bypass was demonstrated in #296/#297. Draft #285 is not included.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-02T03:17:15.278749Z 9942d3e PR opened
🔒 Security Review ✅ Completed 2026-10-02T03:11:33.770080Z 9942d3e PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

thsnkhn commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Candidate validation on head 173034d7d2597af6ef40e9e8d8dab999978fc611 (runtime source unchanged from 9942d3e):

  • All 1,236 Go tests passed with PostgreSQL 17; no individual tests skipped. go vet ./... passed.
  • All 110 Studio tests and embedded production build passed. Chromium exercised affected form flows against mocked API transport.
  • Focused CLI/data/import/worker race tests passed. TTY, CI, TERM=dumb, redirected output, cancellation and instant-command progress smoke passed.
  • All six candidate archives built; all archive/installer/license SHA-256 checksums verified; Linux archive smoke passed.
  • Actual published v0.0.6 installer/binary created a project, resolved real dependencies, built its runner and prepared PostgreSQL. Candidate v0.0.7 replaced that binary and reported the correct version.
  • The existing v0.0.6 project upgraded to candidate v0.0.7, refreshed Core/Studio assets and runner, rebuilt successfully, migrated PostgreSQL, connected, and served health plus embedded JS/CSS. Because v0.0.7 is not yet published, this pre-publication project-upgrade test used an isolated file module proxy containing the candidate Git source; the final published release will be retested through the real distribution path.
  • Initial CI workflow validation rejected a matrix expression in shell. Replaced it with explicit PowerShell 7 and 5.1 steps; native Linux/macOS/Windows CI is now running on the corrected head. This was a workflow configuration failure, not a native installer pass.

@thsnkhn
thsnkhn merged commit b40c28f into main Oct 2, 2026
5 checks passed
@thsnkhn
thsnkhn deleted the codex/release-audit branch October 2, 2026 03:13

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9942d3eb98

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/install.sh
Comment on lines +52 to +53
trap 'exit 130' INT
trap 'exit 143' TERM

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Forward termination to the active installer child

When a supervisor sends SIGTERM directly to the installer PID while it is waiting on a foreground curl, the shell defers this trap until curl exits; because the downloads have no total timeout, a stalled download can keep the installer alive indefinitely instead of cancelling. This is reproducible with a sleeping fake curl (kill -TERM <installer-pid> leaves the installer running), while the new cancellation test misses it because its fake child exits immediately after signaling the parent. Forward termination to the active child or process group.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed independently on published v0.0.7 with real curl and parent-only SIGTERM. Tracked precisely in #301 (related #273) and fixed in PR #305 using tracked asynchronous curl + interruptible wait and owned-child termination/reaping. Six real stalled-HTTP regressions cover metadata/archive/checksums × INT/TERM; native macOS CI pending on final head. Existing v0.0.7 remains untouched.

Comment on lines +239 to +242
defer func() {
cancel()
w.shutdownActiveExecutions(ctx, &inFlight, active, options)
}()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Cancel sibling queues before draining the failed queue

When one queue encounters a Store or finalization error while an active handler ignores cancellation, this defer waits up to ShutdownTimeout and may then spend another timeout expiring claims before runQueueLoop returns the error. runContinuous does not cancel the shared worker context until it receives that return, so sibling queues can continue claiming and starting executions throughout the drain interval. Notify or cancel the worker before performing the bounded per-queue cleanup.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed independently: sibling queues can start new work during failed queue drain/expiry. Follow-up #302 and PR #305 publish the originating error and cancel shared worker context before local cleanup, preserving the original error against sibling cancellation races. Deterministic two-queue/slow-expiry regression passes with -race and fails on v0.0.7. Original #294 per-queue cleanup remains intact.

const showForm = computed(() => Boolean(entityMeta.value) && (isNew.value || Boolean(record.value)))
const dirty = computed(() => fields.value.some((field) => !draftValuesEqual(draft.value[field.name], baseline.value[field.name])))
const canSave = computed(() => showForm.value && dirty.value && !loading.value && !saving.value && !isSystem.value)
const canSave = computed(() => showForm.value && (isNew.value || dirty.value) && !loading.value && !saving.value && !isSystem.value)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep Create disabled after a successful mutation

If the create succeeds but router.replace is delayed, aborted, or throws, mode remains new and this expression becomes true again as soon as the mutation stops pending. Because resetToRecord no longer disables saving through dirty, the broad catch leaves the successfully created form enabled indefinitely, and another click or save shortcut POSTs a duplicate Record. Track the completed create/navigation state so Create remains disabled until the route changes.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed with narrower disposition: aborted/thrown navigation allows another user-triggered POST; mere pending navigation is protected by existing command in-flight gating. #303 / PR #305 retain committed-create state, disable further create and provide navigation-only recovery. Actual production UI Chromium button/shortcut cases cover pending, abort, reject, successful navigation and failed-mutation retry.

const showForm = computed(() => Boolean(entityMeta.value) && (isNew.value || Boolean(record.value)))
const dirty = computed(() => fields.value.some((field) => !draftValuesEqual(draft.value[field.name], baseline.value[field.name])))
const canSave = computed(() => showForm.value && dirty.value && !loading.value && !saving.value && !isSystem.value)
const canSave = computed(() => showForm.value && (isNew.value || dirty.value) && !loading.value && !saving.value && !isSystem.value)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Omit untouched defaults from permission-scoped creates

For a user with create permission but deny-write on a defaulted field, enabling an untouched new form here still cannot create the Record: new-form payload construction submits every metadata default, so the server evaluates the protected field's FieldWrite predicate and rejects the request. An empty payload would allow PostgreSQL to apply the same default without writing the denied field, so untouched defaults should be omitted unless the user changes them.

AGENTS.md reference: AGENTS.md:L97-L101

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed: untouched ordinary metadata defaults are explicitly sent and rejected by FieldWrite, while empty input lets PostgreSQL supply the same default. #304 / PR #305 omit ordinary untouched database-backed defaults and use exact stored defaults for scoped row/conditional-field authorization under a transaction-held INSERT table lock. Explicit denied writes stay denied; precision/date/naming/hooks regression-tested. Format-naming token defaults remain explicit because current naming requires input, a documented scope boundary.

thsnkhn commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Published v0.0.7 from clean main b40c28f via successful release workflow 36959982701.

All 10 assets are present; every listed SHA-256 checksum passed. Final public Linux AMD64 fresh installation and actual v0.0.6-to-v0.0.7 CLI/project upgrade passed with public Go module resolution, runner builds, PostgreSQL preparation/migration, preserved test data, health and embedded Studio assets. Current-version/no-op upgrade passed.

Native candidate installer/update tests also passed on macOS ARM64 and Windows AMD64 (PowerShell 7 and 5.1). Linux ARM64, macOS AMD64 and Windows ARM64 were cross-built and inspected only, not executed natively. Full Go/PostgreSQL tests (1,236), Studio tests (110), vet, focused race checks and exact-head CI passed.

The installer subset is shipped; #273 remains open for discovery/uninstall work. Other deferred audit findings remain tracked in #143, #291 and #296–#299.

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