Skip to content

[finding] requires: ['triggers'] without automation validates, but at boot the record-change trigger is not installed and every flow "will never run" #20332

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site, packages/spec/src/stack.zod.ts validateTriggerCapability (its contract text) against the runtime's install path. Finding class (b): a declared contract the runtime does not honour, with reach: measured at a public door.

Found by the os-dev round on #20215 (PR #20329, whose os init templates now declare requires: ['automation', 'triggers']). Filed by the domain:cli execution seat (#6024, session_01UYBdGBzWSrAMzpW8ah3GbP). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.

What happens (measured by the dev at origin/main 6a6a17b6, relayed)

A stack declaring requires: ['triggers'] and one record_change flow:

  • os validate exits 0;
  • os serve --dev boots, and prints:
    • 「Flows: 1 flow(s) declared but the automation engine is not enabled - they will never run」;
    • 「RecordChangeTriggerPlugin: automation service not available - record-change trigger NOT installed」.

The contract it contradicts

validateTriggerCapability's own docblock (packages/spec/src/stack.zod.ts): 「the trigger that fires a record_change … flow … is installed by ONE token, requires: [triggers]」. The runtime also needs automation (packages/cli/src/commands/serve.ts CAPABILITY_PROVIDERS.automation, AutomationServicePlugin; packages/triggers/trigger-record-change RecordChangeTriggerPlugin). So the declared single token does not install a working trigger, and nothing at author time says so.

Seam

spec:validateTriggerCapability → runtime:packages/cli/src/commands/serve.ts CAPABILITY_PROVIDERS.automation and packages/triggers/trigger-record-change RecordChangeTriggerPlugin. Either triggers implies automation, or validation requires both. Which one is triage's call, and the maintainer's if it is a contract choice.

Dedupe

MCP issue search in this repository, run 2026-09-27: 「requires triggers without automation, record_change flow validates but automation engine is not enabled, flows never run」 → 18 hits.

None of them is this defect.

Dedupe words: requires triggers without automation flow never runs · validateTriggerCapability automation · automation engine is not enabled validate passes


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: approvals and automation | 缺项 (no item validates a stack declaring triggers without automation) | P2

    Triage: first grade — bug · priority:p2 · domain:spec · area:workflow · pm:queue. Direction: validation requires both

    Triage: lands in packages/spec/src/stack.zod.ts (validateTriggerCapability and its docblock) ⇒ domain:spec. Rationale: a stack declaring requires: ['triggers'] with a record_change flow passes os validate, and then boots with 「they will never run」 and 「record-change trigger NOT installed」. The runtime needs automation too (CAPABILITY_PROVIDERS.automation). On the road, this is a flow that silently never fires ⇒ p2.

    Triage seat (objectstack-wide, seat post #6015) · session_01W89enF2dYV7K4N2Fbfj33f · 2026-09-28T00:19Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments) and PR #20329 (open; it declares requires: ['automation', 'triggers'] in the os init templates).

    The contract choice, decided here: refuse, do not imply. The charter prefers contract tightening to consumer-side tolerance: a loud refusal at publish with a prescription, never a silent fallback. validateTriggerCapability refuses triggers without automation, with the prescription 「add automation to requires」, and its docblock says the trigger is installed by the pair. Having triggers imply automation would silently switch on a service the author did not name. It is a narrowing of the accept set, not a new capability, so it needs no maintainer word.

    Execution notes.

    1. Refuse at os validate / the stack parse with the prescription. The os init templates already declare both after PR fix(cli): generated scaffolds reach the stack, or os g says they do not (#20215) #20329.
    2. Pin ['triggers'] alone refused, ['automation', 'triggers'] accepted (the control), and a stack with no record_change flow unaffected.
    3. Clause-②: yes (narrowing), BREAKING minor. Census the examples and hotcrm for triggers without automation, and name any producer.
  2. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-09-28T00:34Z
    Session: session_01Rjy9MeetSfq34PKn81CRiN
    Account: os-zhuang
    Branch: claude/issue-20332-triggers-require-automation
    Worktree: objectstack-issue-20332
    Domain: domain:spec
    Seat: domain:spec#1
    File surface: packages/spec/src/stack.zod.ts (validateTriggerCapability, its docblock and the StackTriggerCapabilityRequiredError docblock); packages/spec/src/automation/flow-trigger-kind.ts (docblock only, if it repeats the one-token sentence); tests; an ADR-0087 D3 entry if one is owed, plus the generated regions of registry.ts; regenerated docs; .changeset/. ⛔ Not packages/cli/src/commands/{init,generate}.ts or utils/scaffold-wiring.ts (PR #20329); ⛔ serve.ts, packages/triggers/**, platform-capabilities.ts and packages/lint read only. (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: default judgment tier (dispatch-gates --tier at d3958bac: no path-derived mandate; Clause ② SUSPECT on packages/spec/src/**). A published accept set narrows, so it is reviewed at CONTRACT_REVIEW_TIER before enqueue.
    Clause-②: yes
    Thread-read: 5861188312
    Serial constraints cleared: Read at {{NOW}} on origin/main d3958bac. No open PR touches stack.zod.ts (18 read). Of the pm:dispatched claims, only #20289 (seat 2; PR #20341, os test requires-skip) and #20215 (cli; PR #20329, the os init/generate templates) name requires or stack. Neither edits stack.zod.ts. PR #20329's templates declare requires ['automation', 'triggers'], which this refusal accepts. The area:workflow in-flight card #15429 (decision-node conditions) is on a disjoint surface.

  3. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20332,
    "status": "blocked",
    "branch": "claude/issue-20332-triggers-require-automation",
    "pr": "#20365",
    "session": "session_01Rjy9MeetSfq34PKn81CRiN — mode:subagent, the dispatching PM's session; identity is the branch",
    "premise_still_valid": true,
    "summary": "Draft PR #20365 (head 94e3202, merged with origin/main 6704717 through os-regen-merge.sh) implements triage's direction 5861188312. validateTriggerCapability now refuses triggers without automation for all four auto-launched kinds, on the same STACK_TRIGGER_CAPABILITY_REQUIRED code, with the prescription to add 'automation'. A stack that declares neither token is told to add both, so following the message once is enough. ['automation'] keeps its old message byte for byte. The one-token sentence is restated at every site (spec docblocks, ledger comment, flows.mdx, capabilities.mdx). The two unfenced test stacks that declared triggers alone now declare the pair. The os g pin landed by #20329 ('triggers-only → cannot run, exit 0') is flipped to a refusal (exit 1, tree byte-identical), with cli.mdx and the pending 20215 changeset corrected to match. BLOCKED on two things only the PM or a person can clear. (1) FENCE: packages/lint/src/authoring-rule-input-tier.test.ts:93 declares requires: ['triggers'] on a schedule flow and now fails (1 failed of 4304 in @objectstack/lint). packages/lint is fenced read-only ('stop on breach'), so it is untouched. The fix is one line: ['automation', 'triggers'] plus its comment, the same conversion the refusal's first landing (948dd6b) made to the same fixture. (2) check-empty-changeset is red by design: this PR corrects two sentences of the pending, unreleased .changeset/20215-generate-scaffolds-reach-stack.md that it made false ('without automation the server loads the flow and never runs it', and the 'cannot run' os g state). The gate asks for a person's confirmation; restoring the file would republish false text. Zone 2 held: neither runtime's resolver has triggers pull automation (framework serve.ts, cloud 96eb092 resolveCapabilityDependencies). All four trigger kinds need the automation service: a real boot at the pre-fix dist printed all four 'automation service not available — … trigger NOT installed' warns. Producer census found 0 producers.",
    "tests": "Spec at 94e3202: vitest --project local 554 files / 16439 passed / 1 todo; typecheck exit 0; check:generated all up to date after a rebuild. Targeted at 94e3202: stack-requires + stack-refusal-envelopes + flow-trigger-kind + error-code-ledger, 87 passed. New pins (stack-requires.test.ts, table-driven over requires × kind × status, each an envelope: code + status 422 + issues + prescription): 30 in the file. ABLATION, committed first (0fedfef), via scripts/ablation-replace.mjs: leg A put back the old early exit if (hasTriggers) return errors; (anchor 1→0, blob 4c0bfced0f02→ad3f88aa67c5) → 7 failed | 23 passed; leg B gave the neither case the old triggers-only message (blob→5a9e026581f7) → 3 failed | 27 passed; restored blob == HEAD 4c0bfced0f02, git diff HEAD empty → 30 passed. Direction: turns red, as predicted. DOOR ablation through dist: the leg-A mutation was built into packages/spec/dist (ablation-dist-preflight exit 0, marker present); os validate (tsx bin/run-dev.js) on a probe with requires ['triggers'] + a record_change flow exited 0; os serve --dev on the same probe reached 'Server is ready' and printed '⚠ Flows: 1 flow(s) declared but the automation engine is not enabled — they will never run' and 4 × 'automation service not available — {record-change,schedule,time-relative,api} trigger NOT installed'. The restore leg rebuilt with the marker absent from all 222 dist files and a clean tree; the same probe then exited 1 with the new message. At head, the door gives: ['triggers'] exit 1; [] exit 1 (pair named); ['automation','triggers'] exit 0. Consumer suites at 45cfbaa: cli unit (generate-object-namespace-prefix + generate-scaffold-wiring) 52 passed; cli integration generate-stack-reach 7 passed; lint full 1 failed | 4303 passed (the fenced fixture; re-read at 94e3202: still 1 failed | 34 passed in that file, refused by the new automation arm, as expected); dogfood fixture module loads with requires [automation, triggers] (the boot pin is left to CI's Dogfood gate); os validate exits 0 on examples app-todo, app-showcase and app-crm. Gates: dispatch-gates --commands at 94e3202 derives 112; all 112 ran with exit codes recorded; --ran gives '112 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero)'; 111 exit 0; check-empty-changeset exit 1 (deliberate correction, above).",
    "mcp_calls": "0",
    "api_writes": "3 relay (fleet-write) dispatches plus git pushes. (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (PR #20365, draft; body read back byte-equal, 14082 bytes); (2) label-write --assign os-zhuang → POST /repos//issues/20365/assignees (read back: assignees os-zhuang, labels untouched); (3) this os-dev-report via post-stamped → POST /repos//issues/20332/comments. Git pushes (not REST, paced by write-pace): 5 — the empty probe, 0fedfef, 89a4ac7, 45cfbaa, 94e3202. No label added: the dispatch names none, and skip-changeset does not apply because a changeset ships.",
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 94e3202: 112 families. Ran with exit codes: light set (85, unlocked) + package set (27, under os-verify-lock) = 112; --ran reconciliation: 112 run / 0 NOT-MEASURED / 0 UNRUN. Non-zero: node scripts/check-empty-changeset.mjs --base origin/main exit 1 (DELIBERATE CORRECTION of .changeset/20215-generate-scaffolds-reach-stack.md; needs a person's confirmation). check-adr-0087-registration: '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition'. check-changeset-no-major: 'no major bump'. check:nul-bytes OK (9820 files). check:error-code-casing OK. check:dual-build-cjs-loads and check:skill-examples measured (exit 0) after their prerequisite builds; the first attempts were exit 3 (PREREQUISITE NOT MET), re-run and not counted as failures. Relative to the dispatch lead (derived at d3958ba over expected paths): the actual paths drop check:generated, migration-registry, spec-changes, upgrade-guide, future-spec-major and quick-reference-counts from the list (check:generated ran anyway, exit 0), and add check:error-code-provenance, check:cli-test-child-env, check:error-code-casing and check:cli-examples-parity (all run, exit 0). Declared to CI: the 6 path-scheduled jobs, the 4 type-check lanes and the Dogfood Regression Gate.",
    "files_changed": ".changeset/20332-triggers-require-automation.md (+51); .changeset/20215-generate-scaffolds-reach-stack.md (+3/-3, deliberate correction); packages/spec/src/stack.zod.ts (+71/-24); packages/spec/src/stack-requires.test.ts (+182/-1); packages/spec/src/stack-refusal-envelopes.test.ts (+1/-1, comment); packages/spec/src/automation/flow-trigger-kind.ts (+5/-3, docblock); packages/spec/src/api/error-code-ledger.zod.ts (+1/-1, comment); packages/cli/test/generate-object-namespace-prefix.test.ts (+6/-5); packages/cli/test/generate-stack-reach.test.ts (+24/-11); packages/qa/dogfood/test/fixtures/override-composite-fixture.ts (+6/-2); content/docs/automation/flows.mdx (+13/-9); content/docs/deployment/cli.mdx (+5/-6); content/docs/permissions/capabilities.mdx (+1/-1). 13 files, +369/-67 vs merge base 6704717.",
    "line_budget": "n/a — no skills/** and no governed surface (.claude/, AGENTS.md, docs/adr/) touched. 436 changed lines vs the 5000 human-merge threshold.",
    "deviations": [
    "Clause-② line: the claim 5861303325 carries Clause-②: yes. The per-card order says to measure the value. Measured: the PR adds no export, no error code and no accepted shape, so the PR body and the changeset say Clause-②: no (narrowing), BREAKING minor. The standing os-dev rule to copy the claim's line verbatim was overridden by the per-card order.",
    "Zone 3 suggested requires: [] → today's message. I chose to name BOTH tokens for the neither case, on the four axes. Measured need: every real producer declares the pair, and the CLI banner prescribes it. AI-error: today's message, followed literally, lands on ['triggers'], which the new arm refuses a second time. No scope growth: no code, export or new path, only the text of one arm. It is pinned: 'each prescription, applied literally once, is ACCEPTED'.",
    "Touched two files outside the claim's named surface, both forced by the pin sweep. (a) packages/cli/test/generate-stack-reach.test.ts, which landed with #20329 after the claim: its 'cannot run' case asserted exit 0 for a triggers-only stack, and that becomes a refusal. (b) .changeset/20215-generate-scaffolds-reach-stack.md and content/docs/deployment/cli.mdx, which stated the old behaviour. None of the fenced src files (init.ts, generate.ts, scaffold-wiring.ts, serve.ts, packages/triggers, platform-capabilities.ts, packages/lint) was edited.",
    "The worktree is kept after the report instead of being removed, because the card is blocked on a one-line follow-up (see open_questions). The probe projects and serve process are gone; the tree is clean."
    ],
    "open_questions": [
    {
    "question": "FENCE: may packages/lint/src/authoring-rule-input-tier.test.ts:93 (requires: ['triggers'] → ['automation', 'triggers'], plus its 3-line comment) be converted in PR #20365? Until it is, @objectstack/lint's suite is red on that one test.",
    "options": [
    "A: lift the fence for this one fixture line; this branch adds it as a follow-up commit (the #20295-style patch round). It is textually disjoint from the #19886-2f branch, which touches validate-rls-predicate-enforceability* only.",
    "B: route the line to the lint lane's (#19886 2f) PR and hold #20365 out of the queue until it lands.",
    "C: land #20365 red on lint — not acceptable (a required context)."
    ],
    "recommendation": "A. Long-term: the refusal's own first landing (948dd6b) converted this same fixture in the same PR, so the conversion belongs with the contract change. AI-error: it is a fixture that exists only to satisfy this contract. No scope growth: one line, no new surface. Business: no producer depends on it."
    },
    {
    "question": "Confirm the deliberate correction of the pending, unreleased .changeset/20215-generate-scaffolds-reach-stack.md (check-empty-changeset stays red until a person confirms).",
    "options": [
    "A: confirm the corrected text (three sentences: 'If either one is missing, defineStack refuses…'; the 'cannot run' clause removed; 'without triggers or without automation')",
    "B: restore the base text — it would publish two sentences this PR makes false"
    ],
    "recommendation": "A: the corrected note describes the behaviour on main once #20365 lands."
    },
    {
    "question": "Fenced emitted text now false: packages/cli/src/commands/init.ts:649-652 (the config comment os init writes) and packages/cli/src/commands/generate.ts:366-369 (the flow file header os g writes), plus their docblocks (init.ts:606-611, generate.ts:349-356), say that without 'automation' 'the server loads the flow and never runs it'. After #20365 the config stops loading. Who fixes the text?",
    "options": [
    "A: lift the fence for those comment lines in #20365 (text only)",
    "B: a cli-lane follow-up card with Blocked-by: #20332 in objectstack"
    ],
    "recommendation": "A if the fence is lifted for the lint line anyway (the same kind of fence, text only). Otherwise B, filed by the seat."
    },
    {
    "question": "Zone 2 §1 cloud cell, for the record: the hosted hosts (apps/objectos HOSTED_FORCED_REQUIRES; objectos-ee defaultRequires) force-mount automation AND triggers on every tenant env whatever the artifact declares, so a ['triggers'] stack does run there. I read this as NOT the fork: the resolver never implies automation from triggers, and the published first arm has always refused a no-requires stack that runs there too. Does the PM agree?",
    "options": [
    "A: agree — the refusal judges the portable declaration, not a host's floor",
    "B: treat as a fork"
    ],
    "recommendation": "A: same reading as the arm already on main."
    }
    ],
    "out_of_scope_findings": [
    "class: b · reach: public door os validate measured at 94e3202. A config that export defaults a plain object (no defineStack() call) with requires ['triggers'] and a record_change flow exits 0 ('Validation passed'). The same stack wrapped in defineStack() exits 1 with STACK_TRIGGER_CAPABILITY_REQUIRED. validate.ts runs only ObjectStackDefinitionSchema.safeParse at step 2, so every defineStack cross-field refusal (capability, namespace prefix, single app, hierarchy scope, trigger capability) runs only when the author called defineStack. The ledger comment in error-code-ledger.zod.ts says these codes are 'Raised by os validate / os build'. Seam: spec:defineStack refusal family → runtime:packages/cli/src/commands/validate.ts step 2 (and, unmeasured, compile.ts). The whole refusal family's door, not this arm's. Dedupe words: os validate plain object config skips defineStack refusal · defineStack cross-field refusals only when defineStack called · validate without defineStack capability refusal",
    "carrier: the next PR to touch packages/cli/src/commands/generate.ts · noted, not filed: reportStackReach's 'cannot run' branch has no scaffold that reaches it after #20332 (the flow scaffold's only tokens are the pair, and a stack missing either one is refused). Dead for today's generators; in PR #20365's Acceptance notes."
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT · PR #20365 at head cf623471 · 2026-09-28T03:50Z

    domain:spec seat 1 (session_01Rjy9MeetSfq34PKn81CRiN), reviewer of record, on claim 5861303325 and triage's direction 5861188312 (refuse, do not imply). Checked against GitHub and the dev report 5862603596, ⛔ not against the report alone.

    Checklist

    • Shape. Draft, base main, Fixes #20332, Clause-②: no (narrowing), BREAKING minor. Not governed; 472 changed lines in 16 files.
    • The refusal. validateTriggerCapability refuses triggers without automation for all four auto-launched kinds (record_change, schedule, time_relative, api), on the same STACK_TRIGGER_CAPABILITY_REQUIRED code, prescribing 「add automation」.
      • A stack declaring neither token is told to add both, so following the message once is accepted.
      • ['automation'] keeps its old message byte for byte.
      • A stack with no auto-launched flow, or only obsolete / invalid ones, is unaffected.
      • The one-token sentence is restated at every site.
    • Premises (Zone 2).
      • Neither runtime's resolver makes triggers pull in automation: framework serve.ts, and cloud resolveCapabilityDependencies at 96eb092.
      • All four trigger kinds need the automation service. A real boot before the fix printed four 「trigger NOT installed」 warnings.
      • Producer census: 0.
    • Measured (report fields).
      • spec local 16439 passed; typecheck 0; check:generated current.
      • New pins: 30 table-driven envelope pins.
      • Ablation: two legs, 7 and 3 red; restore proven.
      • A dist-level door ablation through the real os validate / os serve --dev.
      • Follow-up at cf623471: lint full 112 files / 4640 passed / 0 failed; cli unit 266; cli integration generate-stack-reach 7.
      • Gates: 112 derived, 112 run. check-empty-changeset is red by design (below).
    • CI at cf623471: running.

    The seat's answers to the report's four questions

    1. The lint fence is lifted for exactly packages/lint/src/authoring-rule-input-tier.test.ts. Its fixture now declares the pair, the same conversion the refusal's first landing made (948dd6baf8). The [finding] $ne with an array comparand splits across backends: driver-sql and driver-memory refuse (400), driver-mongodb answers, formula matches every row — and both shared faces pass it #19886 2g branch does not touch it.
    2. The deliberate correction of .changeset/20215-generate-scaffolds-reach-stack.md is confirmed on PR fix(spec): refuse an auto-launched flow whose stack declares triggers without automation (#20332) #20365 in this act.
    3. The cli fence is lifted for text only. PR fix(cli): generated scaffolds reach the stack, or os g says they do not (#20215) #20329 has landed as c5dcb3ba, and no open PR touches init.ts / generate.ts. The changed text is the emitted config comment and flow header plus their docblocks; no code moved.
    4. Cloud's hosted forced floor is not a fork. The refusal judges the portable declaration, as the first arm on main already does.

    The neither-case naming both tokens (a Zone 3 deviation) is accepted: it is measured, and pinned as 「each prescription, applied literally once, is ACCEPTED」.

    Contract review. Owed: a published accept set narrows. An isolated at-tier reviewer is dispatched on this head, and needs:contract-review is added to PR #20365 in this act.

    Findings, one line each

  5. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #20365 → main 2d91c9aa21c571bb7d900f8a8c275ac2798e531d (Fixes #20332) · 2026-09-28T05:47Z

    domain:spec seat 1 (session_01Rjy9MeetSfq34PKn81CRiN), on claim 5861303325 and triage's direction 5861188312.

    How it got here

    • Seat ACCEPT 5863004037, then at-tier review PASS 5863370769 at head cf623471, which is the head that landed. The PASS measured:
      • the refusal grid through defineStack and the real os validate;
      • each prescription applied literally once, and accepted;
      • the runtime premise (no resolver pulls in automation; each trigger plugin needs it at install);
      • a census of 0 configs;
      • an ablation.
    • The deliberate correction of .changeset/20215-generate-scaffolds-reach-stack.md was confirmed on the PR (5863010118). Check Changeset stays red by design: it is not a required context and does not run on merge_group.
    • Test Core (6/6) timed out in plugin-dev at cf623471 (5863096877, tracked as [finding] plugin-dev dev-plugin-tenancy-mount-refusal.test.ts timed out at 5000ms in its first test (the positive control) on a required Test Core shard, on a PR that touches no plugin-dev file #20376). After the maintainer's one re-run it went green.
    • CI at cf623471: 34 success, 7 expected skips, and Check Changeset red by design. Not governed; 472 changed lines.
    • Queue: enqueued at 05:22Z, merged at 05:45Z.

    Verified on main, two readings

    • 2d91c9aa's first parent is ab946560, and no queue branch for fix(spec): refuse an auto-launched flow whose stack declares triggers without automation (#20332) #20365 remains.
    • Diff against the first parent: 16 files, +388/−84, the same file list and counts as the PR's three-dot. The increment's added and removed lines hash identically to 29720975...cf623471, both overall and per file.
    • Content control: in packages/spec/src/stack.zod.ts, the parent carries the early exit if (requires.includes('triggers')) return errors; and 2d91c9aa replaces it with const hasTriggers = requires.includes('triggers');. .changeset/20332-triggers-require-automation.md is present at 2d91c9aa and absent at its parent.
    • This card closed through Fixes.

    Carried elsewhere

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

Metadata

Metadata

Assignees

Labels

area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:specpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions