Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
178 commits
Select commit Hold shift + click to select a range
4136f66
chore(release): sync beta back into development
github-actions[bot] Aug 31, 2026
1fc9ef7
fix(composer): declare ext-xsl so dependabot can resolve (#3201)
rubenvdlinde Aug 31, 2026
fa6b38a
chore(release): sync main back into development
github-actions[bot] Aug 31, 2026
34f1905
Merge pull request #3210 from ConductionNL/sync/main-to-development-2…
rubenvdlinde Aug 31, 2026
07f2713
Merge pull request #3203 from ConductionNL/sync/beta-to-development-2…
rubenvdlinde Aug 31, 2026
8fa9618
chore(deps): take @conduction/nextcloud-vue 2.27.2 (#3214)
rubenvdlinde Aug 31, 2026
36809e1
chore(deps): bump zod from 4.4.3 to 4.5.2 (#3206)
dependabot[bot] Aug 31, 2026
df087fb
chore(deps): bump marked from 12.0.2 to 18.0.11 (#3207)
dependabot[bot] Aug 31, 2026
9c1d3a2
chore(sync): carry beta back into development
github-actions[bot] Aug 31, 2026
c6cb8e0
Merge pull request #3222 from ConductionNL/sync/beta-to-development-2…
rubenvdlinde Aug 31, 2026
e27bde1
docs(license): state the apexcharts licence accurately in the overrid…
rubenvdlinde Aug 31, 2026
40da9a4
chore(release): 2.0.9-unstable.20260831133308 (#3225)
github-actions[bot] Aug 31, 2026
b1f17ad
chore(release): sync main back into development
github-actions[bot] Aug 31, 2026
0485aea
chore(sync): carry beta back into development
github-actions[bot] Aug 31, 2026
10a4525
Merge pull request #3229 from ConductionNL/sync/beta-to-development-2…
rubenvdlinde Aug 31, 2026
e6acacc
fix(deps): make the npm overrides follow their direct dependency (#3232)
rubenvdlinde Aug 31, 2026
b957cae
fix(db): bind catch(Exception) to a class that exists, and drop dead …
rubenvdlinde Aug 31, 2026
015a254
Merge pull request #3227 from ConductionNL/sync/main-to-development-2…
rubenvdlinde Aug 31, 2026
07b58b0
fix(db): remove an impossible lastInsertId fallback and a duplicate g…
rubenvdlinde Aug 31, 2026
f26b368
fix(archival): call a mapper method that exists, and correct a @throw…
rubenvdlinde Aug 31, 2026
5c5a734
docs(license): correct the apexcharts MIT boundary and record the OEM…
rubenvdlinde Aug 31, 2026
290b35d
fix(chat): send temperature through modelOptions, where LLPhant reads…
rubenvdlinde Aug 31, 2026
99aaccc
docs(cache): declare the warmup_breakdown key the stats array actuall…
rubenvdlinde Aug 31, 2026
ce8b4f4
chore(release): 2.0.11-unstable.20260831184325 (#3246)
github-actions[bot] Aug 31, 2026
e10e5bc
feat(schemas): let an app retire a schema from its descriptor (#3248)
rubenvdlinde Aug 31, 2026
842ba50
feat(organisation): carry the four chain-partner fields it lacked (#3…
rubenvdlinde Aug 31, 2026
67cc872
spec(flow-portal-task): a portal-task node that asks a party outside …
rubenvdlinde Sep 1, 2026
37dd618
chore(n8n): retire the n8n register descriptor (#3251)
rubenvdlinde Sep 1, 2026
72fa00a
spec(flow-runs-subject-scope): the case page's view of the engine (#3…
rubenvdlinde Sep 1, 2026
6fc19be
chore(release): 2.0.12-unstable.20260901050305 (#3256)
github-actions[bot] Sep 1, 2026
9ef9ff8
feat(flow): a case page's view of the engine, scoped to one subject (…
rubenvdlinde Sep 1, 2026
5e0df04
feat(flow): send-notification, send-email and send-talk-message nodes…
rubenvdlinde Sep 1, 2026
b42da68
chore(deps): nextcloud-vue 2.28.0, and an npm override that resolves …
rubenvdlinde Sep 1, 2026
40bab56
fix(controllers): name the register before the schema
rubenvdlinde Sep 1, 2026
293736f
chore(lint): let the linter see tests/ and scripts/ (#3265)
rubenvdlinde Sep 1, 2026
d99e3bc
Merge pull request #3266 from ConductionNL/fix/resolve-register-befor…
rubenvdlinde Sep 1, 2026
ddbbeba
feat(flow): the task entity — a suspension becomes a queryable row (#…
rubenvdlinde Sep 1, 2026
6e2e2af
feat(flow): parallel streams — independent branches of one run advanc…
rubenvdlinde Sep 1, 2026
63da91d
fix(controllers): two more inverted call sites, and a guard that can …
rubenvdlinde Sep 1, 2026
6a48669
Merge pull request #3277 from ConductionNL/fix/register-order-any-rec…
rubenvdlinde Sep 1, 2026
90a37fe
feat(flow): the openregister.user-task node puts a person into the gr…
rubenvdlinde Sep 1, 2026
cfad0da
feat(router): move openregister off hash routing, and stop the catch-…
rubenvdlinde Sep 1, 2026
985d351
feat(flow): task inbox projections, notifications you can answer, a V…
rubenvdlinde Sep 1, 2026
a099d56
feat(flow): the case layer — CMMN semantics as rows on the object (fl…
rubenvdlinde Sep 1, 2026
ca4f2e6
chore(sync): carry beta back into development
github-actions[bot] Sep 1, 2026
2fffbe9
Merge pull request #3294 from ConductionNL/sync/beta-to-development-2…
rubenvdlinde Sep 1, 2026
f9c4b10
feat(flow): the portal-task node, the external performer type and the…
rubenvdlinde Sep 1, 2026
562724a
feat(flow): task forms, the fields a user task's completion supplies …
rubenvdlinde Sep 1, 2026
9e6bb06
fix(flow): imported flows fire (id/slug seam) and can be adopted (#3285)
rubenvdlinde Sep 1, 2026
7a12cf6
feat(flow): durable business timers, one clock for SLA, opschorting a…
rubenvdlinde Sep 1, 2026
44843c6
fix(e2e): give occ a maxBuffer so the worker scenarios stop self-skip…
rubenvdlinde Sep 1, 2026
027ed41
fix(e2e): follow the router off hash routing in the three specs that …
rubenvdlinde Sep 1, 2026
d075694
build(guard): fail the build when two Dexie versions ship in one chun…
rubenvdlinde Sep 1, 2026
82ed322
feat(approval): consolidate the approval engine onto ordered task seq…
rubenvdlinde Sep 1, 2026
14bd30f
fix(flow): resume reads the live subject, routed items reach their br…
rubenvdlinde Sep 1, 2026
9b32ca0
chore(release): 2.0.14-unstable.20260901212512 (#3314)
rubenvdlinde Sep 1, 2026
cfa9647
fix(e2e): repair the two specs history routing broke on development (…
rubenvdlinde Sep 1, 2026
865d212
feat(tasks): wire the fleet task inbox into the UI (#3315)
rubenvdlinde Sep 2, 2026
eeedb7b
fix(flow): a resume answers only the node whose slot it answers, and …
rubenvdlinde Sep 2, 2026
81e3dd1
fix(flow): the await-signal answer lands in the item's record, not be…
rubenvdlinde Sep 2, 2026
d1594cc
feat(flow): a decision-table node puts rule evaluation into the graph…
rubenvdlinde Sep 2, 2026
24a7516
feat(flow): the engine owns the two seams every consumer was rebuildi…
rubenvdlinde Sep 2, 2026
2839ab9
fix(search): count only the chunk owners the caller can actually see …
rubenvdlinde Sep 2, 2026
17a4478
test(e2e): the VTODO deep link serves the shell, it no longer redirec…
rubenvdlinde Sep 2, 2026
2c23de6
fix(tenant): follow the merge before the UUID becomes a scope (#3336)
rubenvdlinde Sep 2, 2026
246222d
feat(tasks): task expiry enforcement and configurable timeout/reject …
rubenvdlinde Sep 2, 2026
501136a
Takes nextcloud-vue 2.31.1 so a hovered KPI tile stops drawing a card…
rubenvdlinde Sep 2, 2026
8783ce6
fix(federation): a federated create may not address an existing object
Sep 3, 2026
2740ada
style(dsar): drop the else phpmd flagged
Sep 3, 2026
709a855
docs(federation): the @spec tag gate-16 asked for
Sep 3, 2026
85e8321
Merge pull request #3345 from ConductionNL/fix/federated-create-canno…
rubenvdlinde Sep 3, 2026
63ad6ff
feat(quality): the quality assessment is @self metadata, not object data
Sep 3, 2026
1eb6823
Merge pull request #3348 from ConductionNL/feat/quality-is-self-metadata
rubenvdlinde Sep 3, 2026
4309cec
feat(flow): a user task arms its own deadline (#3350)
rubenvdlinde Sep 3, 2026
7b576fb
fix(tests): three extraction tests asserted nothing and could not fai…
rubenvdlinde Sep 3, 2026
2accc47
fix: two silent setters, and the warnings that were pointing at them …
rubenvdlinde Sep 3, 2026
afb1f00
feat(organisations): adopt a leaf app's organisations without losing …
rubenvdlinde Sep 3, 2026
6e8bc8f
feat(files): a publication window on the file, so an attachment needs…
rubenvdlinde Sep 3, 2026
925c204
fix(flow): the heartbeat recovers a missed signal instead of rolling …
rubenvdlinde Sep 3, 2026
f3f4abc
feat(tasks): find the newest sequence for a template, across every an…
rubenvdlinde Sep 3, 2026
b8eb72e
test(flow): cover the heartbeat recovery paths that no test executed …
rubenvdlinde Sep 3, 2026
8781660
feat(organisations): project the organisation as an object so a $ref …
rubenvdlinde Sep 3, 2026
0961e89
fix(deferral): register the shutdown flush through a closure, and tes…
rubenvdlinde Sep 3, 2026
c130aa2
fix(nav): let users reach Personal settings again (#3367)
rubenvdlinde Sep 3, 2026
4f3ef5e
fix(ci): a standing release PR ran every development push twice (#3370)
rubenvdlinde Sep 3, 2026
f4d2ddc
chore(deps): nextcloud-vue 2.35.1
rubenvdlinde Sep 3, 2026
9c05d71
Merge pull request #3376 from ConductionNL/chore/nc-vue-2.35.0
rubenvdlinde Sep 3, 2026
8fabe08
feat(apphost): host the store, so an app declares one instead of writ…
rubenvdlinde Sep 3, 2026
13278d5
fix(spec): complete the @spec anchor truncated mid-slug (#3374)
rubenvdlinde Sep 3, 2026
9a31f34
A translatable name field was stored as raw JSON (#3366)
rubenvdlinde Sep 3, 2026
ac65de7
feat(nav): move Reports into the footer chrome (#3379)
rubenvdlinde Sep 3, 2026
4112b93
feat(flow): one flow engine, and it is ours (#3382)
rubenvdlinde Sep 3, 2026
d103596
feat(store): let the store exchange configuration instead of rows
rubenvdlinde Sep 3, 2026
edf875d
docs(store): say plainly that a schema allowlist cannot gate a config…
rubenvdlinde Sep 3, 2026
ff47bf9
fix(store): satisfy phpmd, and cover resolve and the bundle paths
rubenvdlinde Sep 3, 2026
1d03a0f
test(store): cover the controller's federated branches
rubenvdlinde Sep 3, 2026
52ffe23
fix(nav): let an admin reach the admin settings again
rubenvdlinde Sep 3, 2026
d990457
test(store): cover the catalogue's remaining branches
rubenvdlinde Sep 3, 2026
96fd3aa
Merge pull request #3389 from ConductionNL/fix/main-menu-forwards-is-…
rubenvdlinde Sep 3, 2026
eb3f616
Merge pull request #3386 from ConductionNL/feat/store-over-federated-…
rubenvdlinde Sep 3, 2026
c10e017
chore(deps): nextcloud-vue 2.36.0
rubenvdlinde Sep 3, 2026
8ab6f29
Merge pull request #3392 from ConductionNL/chore/nc-vue-2.35.5
rubenvdlinde Sep 3, 2026
bbd743e
fix(apphost): let an app bind the store controller without the full b…
rubenvdlinde Sep 4, 2026
7487bb8
chore: drop an unrelated dependency pin from this branch
rubenvdlinde Sep 4, 2026
4f529b4
fix(render): an imported $ref still resolves its object source (#3385)
rubenvdlinde Sep 4, 2026
55f8511
feat(store): let a store declare its discovery source
Sep 4, 2026
78c29f0
feat(store): let a store declare who may install
Sep 4, 2026
ae09940
feat(store): resolve an action posture against the declaring app
Sep 4, 2026
27c1ece
feat(store): install operations other than writing an object
Sep 4, 2026
36afb39
Merge pull request #3394 from ConductionNL/fix/store-route-needs-its-…
rubenvdlinde Sep 4, 2026
fa84085
fix(e2e): dismiss the setup wizard the chrome spec clicks through
rubenvdlinde Sep 4, 2026
7de09a4
Merge pull request #3400 from ConductionNL/fix/chrome-spec-dismisses-…
rubenvdlinde Sep 4, 2026
a16d40e
Merge pull request #3395 from ConductionNL/feat/store-plane-declarati…
rubenvdlinde Sep 4, 2026
37686a1
Merge remote-tracking branch 'origin/development' into feat/store-pla…
Sep 4, 2026
1bbc1f8
Merge pull request #3397 from ConductionNL/feat/store-plane-install-auth
rubenvdlinde Sep 4, 2026
357ca90
Merge remote-tracking branch 'origin/development' into feat/store-pla…
Sep 4, 2026
6f08aa4
Merge pull request #3398 from ConductionNL/feat/store-plane-action-auth
rubenvdlinde Sep 4, 2026
05aa980
Merge remote-tracking branch 'origin/development' into feat/store-pla…
Sep 4, 2026
8b9a51c
Merge pull request #3399 from ConductionNL/feat/store-plane-install-ops
rubenvdlinde Sep 4, 2026
560a928
docs(openspec): specify the OAuth2 token-set kind and its connect flow
Sep 4, 2026
0b4a3f0
feat(chrome): give openregister the Store surface it hosts for everyo…
Sep 4, 2026
f1b57c3
Merge pull request #3402 from ConductionNL/feat/store-surface
rubenvdlinde Sep 4, 2026
3a8ebb1
feat(credential-broker): add the oauth2-token-set credential kind
Sep 4, 2026
f0f02ac
feat(credential-broker): declare seven OAuth2 providers and the conne…
Sep 4, 2026
06d84cb
chore(deps-dev): bump babel-jest from 29.7.0 to 30.5.0 (#3322)
dependabot[bot] Sep 4, 2026
4ea1abf
chore(deps): bump vue-codemirror6 from 1.6.1 to 1.6.2 (#3319)
dependabot[bot] Sep 4, 2026
4b03f24
chore(deps-dev): bump @vue/test-utils from 2.4.11 to 2.5.0 (#3318)
dependabot[bot] Sep 4, 2026
33f56b0
chore(deps): bump @nextcloud/vue from 9.9.0 to 9.11.0 (#3317)
dependabot[bot] Sep 4, 2026
2ac56a9
chore(deps): bump zod from 4.5.2 to 4.5.4 (#3316)
dependabot[bot] Sep 4, 2026
88ced7d
fix(search): make the isnull filter operator real, and delete the dec…
rubenvdlinde Sep 4, 2026
3695d2d
feat(credential-broker): connect, callback and relay for an OAuth2 to…
Sep 4, 2026
24154ac
feat(credential-broker): a connected accounts panel in personal settings
Sep 4, 2026
fa805d7
feat(leaves): load a leaf's client half on consuming pages (#3404)
rubenvdlinde Sep 4, 2026
45d699f
feat(objects): raw append and expiry purge for high-volume leaf writers
rubenvdlinde Sep 4, 2026
a5c55c4
fix(retention): enforce search trail retention in the hourly cleanup job
rubenvdlinde Sep 4, 2026
4c33cf4
chore(tests): licence headers on the raw append and retention tests
rubenvdlinde Sep 4, 2026
96620b2
fix(credential-broker): call the four things that were written and ne…
Sep 4, 2026
5ca52d5
docs(contract): declare the two raw entry points as an announced cont…
rubenvdlinde Sep 4, 2026
cabd410
Merge pull request #3407 from ConductionNL/feat/raw-append-and-search…
rubenvdlinde Sep 4, 2026
d9862cd
refactor(credential-broker): split the connect service, and mend a ho…
Sep 4, 2026
efa4846
fix(flows): stop the flow migration copying non-flow objects, and rem…
rubenvdlinde Sep 4, 2026
4a6bdf9
docs(openspec): specify what shipped, and tick both changes
Sep 4, 2026
5dc59ee
test(credential-broker): the disconnect endpoint had no test at all
Sep 4, 2026
d1af968
fix(import): count the objects an import LEAVES ALONE, so a caller ca…
rubenvdlinde Sep 4, 2026
044e30b
fix(tests): filter the audit-trail check on object_uuid, not the inte…
rubenvdlinde Sep 4, 2026
5b3df43
chore(deps): bump conduction/hydra-gates to v1.13.0
rubenvdlinde Sep 4, 2026
553fb39
fix(store): serve the built-in items the manifest declares
rubenvdlinde Sep 4, 2026
96625d9
Merge pull request #3414 from ConductionNL/fix/serve-the-builtin-item…
rubenvdlinde Sep 4, 2026
3c367e2
Merge pull request #3416 from ConductionNL/chore/gate-57-delete-file-…
rubenvdlinde Sep 4, 2026
769b625
fix(objects): a write no longer leaves its scope behind for the next …
rubenvdlinde Sep 4, 2026
97a0784
feat(objects): the organisation projection is writable (#3421)
rubenvdlinde Sep 4, 2026
cda9e9f
fix(tests): the full-chain script asserts two endpoints that no longe…
rubenvdlinde Sep 4, 2026
caf21ab
fix(flow): a run killed by a failing step is failed, not stopped (#3425)
rubenvdlinde Sep 4, 2026
aaa4bb6
Merge pull request #3418 from ConductionNL/feat/credential-oauth2-tok…
rubenvdlinde Sep 5, 2026
c715bb4
fix(deleted): refuse to purge a live object, and an archival record a…
rubenvdlinde Sep 5, 2026
4be2adc
fix(bulk): make bulk delete actually delete, account for every row, a…
rubenvdlinde Sep 5, 2026
12d9236
fix(schemas): close the fourth delete door on archival schemas (#3432)
rubenvdlinde Sep 5, 2026
ae5a476
fix(configurations): the import endpoint 500s on a descriptor carryin…
rubenvdlinde Sep 5, 2026
5c9fb7a
fix(gdpr): retention wins over erasure, and over the cascade (#3436)
rubenvdlinde Sep 5, 2026
547b897
fix(deps): bump nextcloud-vue so the manifest schema accepts a config…
rubenvdlinde Sep 5, 2026
c18e5c2
fix(schemas): prune-retired missed a duplicate row and miscounted wha…
rubenvdlinde Sep 5, 2026
6e4793d
fix(quality): the phpmd findings and the mis-measured schema baseline…
rubenvdlinde Sep 5, 2026
b7c1306
feat(setup): ask which example data to load, as cards, instead of a b…
rubenvdlinde Sep 5, 2026
d5b57af
feat(locking): run-scoped object locks that actually refuse a write (…
rubenvdlinde Sep 5, 2026
ea8d028
fix(roadmap): the Suggest-feature control is a link now, and the spec…
rubenvdlinde Sep 5, 2026
229a04d
fix(e2e): the demo-data test arranges the choice it asserts against (…
rubenvdlinde Sep 5, 2026
5c6d249
fix(migrations): a migration that ships without a version bump reache…
rubenvdlinde Sep 5, 2026
d85a0b8
chore(release): 2.0.15-unstable.20260905143606 (#3453)
rubenvdlinde Sep 5, 2026
68cf0fb
fix(locking): a parked run keeps its locks, and the lock nodes exist …
rubenvdlinde Sep 5, 2026
fbd102a
fix(folders,locking): a system context is recognised, and PATCH answe…
rubenvdlinde Sep 5, 2026
26684ff
fix(e2e): dismiss the setup wizard, not just the walkthrough (#3458)
rubenvdlinde Sep 5, 2026
067d1b9
test(locking): e2e coverage for run-scoped object locking, each leg p…
rubenvdlinde Sep 5, 2026
801cc02
feat(flow): anchor a task read to one run, and give a run an address …
rubenvdlinde Sep 6, 2026
85dd862
spec(flow): plan the ask-node programme as three changes (#3464)
rubenvdlinde Sep 6, 2026
dca60d5
fix(flow): a task form's answers reach the steps that follow (#3468)
rubenvdlinde Sep 6, 2026
c83ebcc
fix(l10n): the json catalogues are the source, so put the two flow st…
rubenvdlinde Sep 6, 2026
15d9832
fix(ci): the unit gate runs in a container that has no git (#3466)
rubenvdlinde Sep 6, 2026
de1bed0
fix(gates): the run address names the spec it implements, and why it …
rubenvdlinde Sep 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Empty file added --help
Empty file.
16 changes: 16 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,20 @@ if git diff --cached --name-only | grep -qE "^openspec/(specs/|features\.overlay
fi
fi

# A NEW MIGRATION NEEDS A VERSION BUMP, and this is the cheapest place to be
# told. Nextcloud reads an app's migration files only when appinfo/info.xml's
# <version> is greater than the installed_version it recorded, so a migration
# committed without a bump runs on no existing instance and says nothing about
# it. CI (merge-hygiene) is the enforcement; this only tells you earlier.
#
# WARN ONLY, like everything else in this hook: a commit is a fine moment to
# learn about it and a bad moment to be blocked, and the bump is often the last
# thing you write. The gate on the PR is what actually holds the line.
if git diff --cached --name-only --diff-filter=A | grep -q "^lib/Migration/.*\.php$"; then
if ! php scripts/check-migration-version-bump.php >/dev/null 2>&1; then
echo "pre-commit: WARNING — this change adds a migration without moving <version> in appinfo/info.xml." >&2
echo " Run: php scripts/check-migration-version-bump.php" >&2
fi
fi

exit 0
30 changes: 30 additions & 0 deletions .github/workflows/api-test-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,36 @@ jobs:
# than 40 lines later where it reads as a dependency-install failure.
docker exec nextcloud php /usr/local/bin/composer --version

- name: Provide git inside the container
# Same shape as the composer step above, and for the same reason: the
# unit suite runs INSIDE the nextcloud container, and that image ships
# no git.
#
# MigrationVersionBumpCheckTest builds a small repository per case and
# runs scripts/check-migration-version-bump.php over it, because a test
# that inspects THIS repository can only report whatever today's branch
# happens to look like. With no git the fixtures are never created, so
# all six repository cases failed with
#
# /tmp/or-migration-gate-256a137d7fd3 is not a git repository
#
# which reads as a defect in the gate rather than an absent binary.
# Measured 2026-09-06: this job had failed on all eight development
# pushes since the gate landed in #3451, and `git --version` in the
# container answers `command not found`. With git present the class
# passes 8/8.
#
# apt rather than `docker cp` of the runner's binary: git is not a
# single file like the composer phar, and a copied binary would leave
# its shared libraries and helper programs behind.
run: |
set -e
docker exec -u root nextcloud bash -lc \
'apt-get update -qq && apt-get install -y -qq --no-install-recommends git'
# Prove it is usable HERE, as the user the suite runs as, rather than
# 40 lines later where it reads as a broken gate.
docker exec -u www-data nextcloud git --version

- name: PHPUnit unit suite (in-container, HARD GATE)
# The unit suite requires the full Nextcloud runtime — the OCP stubs
# reference Doctrine\DBAL\* and OC\* internals that only resolve once
Expand Down
26 changes: 25 additions & 1 deletion .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,31 @@ permissions:

jobs:
quality:
if: github.event_name != 'push' || github.event.created != true
# SECOND CLAUSE: skip the run a STANDING release PR triggers.
#
# `Release: merge development into beta` is permanently open with
# `head_ref: development`, so every push to development fires this
# workflow TWICE on the SAME sha — once for `push`, once for that PR's
# `pull_request` event. The concurrency block above deliberately gives
# them separate lanes so the push run is not cancelled, which is right,
# and the consequence is that both run to completion.
#
# The PR run is the redundant one, not the push run: its head sha IS
# development's, which the push run already decided, and the push run
# carries jobs the PR run does not (Coverage Baseline Check, SBOM,
# Features Extract). Measured 2026-09-03: runs 33747123932 (push) and
# 33747129312 (pull_request), same sha b8eb72e2, four seconds apart.
#
# 20 of the fleet's 21 apps carry `beta` in `pull_request.branches` and
# so pay this on every development push. Removing `beta` from that list
# would also work and is worse: the `release/v*` and `sync/main-to-beta`
# PRs genuinely need their run, and they target `beta` too.
#
# A `development -> main` promotion PR is skipped by the same clause, for
# the same reason and just as correctly.
if: >-
(github.event_name != 'push' || github.event.created != true)
&& (github.event_name != 'pull_request' || github.head_ref != 'development')
uses: ConductionNL/.github/.github/workflows/quality.yml@main
with:
app-name: openregister
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/merge-hygiene.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ jobs:
name: Conflict markers and PHP syntax
runs-on: ubuntu-latest
steps:
# FULL HISTORY, deliberately. The migration/version check below compares
# this branch against the merge base with `development`, and a depth-1
# checkout has no merge base to find — it would report "no verdict" on
# every run, which is the silent skip the check exists to remove.
- uses: actions/checkout@v4
with:
fetch-depth: 0

# Conflict markers, anywhere in the tree we author. A marker means a merge
# was committed half-finished; every downstream signal from that commit is
Expand Down Expand Up @@ -69,6 +75,30 @@ jobs:
php-version: '8.3'
coverage: none

# A MIGRATION THAT SHIPS WITHOUT A VERSION BUMP REACHES NOBODY.
#
# Nextcloud runs an app's migrations only when appinfo/info.xml's
# <version> is greater than the installed_version it recorded. Equal
# versions mean `occ upgrade` answers "No upgrade required.", exits 0, and
# reads none of the migration files — no log line, no failure, and the
# feature that needed the table is simply absent.
#
# Measured on a throwaway NC 34 rig 2026-09-05: a migration added with the
# version left alone did not run, was not recorded, and
# `occ migrations:status openregister` reported "Pending Migrations: None"
# while showing 204 executed of 205 available. Bumping only <version>, with
# the code byte-identical, ran it. The version string is the whole gate.
#
# It lives here rather than in Code Quality because it needs the base ref
# and takes milliseconds — the same reason everything else in this file is
# here.
- name: A new migration moves the app version
run: |
set -euo pipefail
BASE="${{ github.event.pull_request.base.ref || 'development' }}"
git fetch --no-tags --prune origin "$BASE"
MIGRATION_VERSION_BASE_REF="origin/$BASE" php scripts/check-migration-version-bump.php

# Every PHP file parses. A conflict marker is caught above, but so is any
# other way a file can be committed unparseable — and this is the check
# that would have failed within seconds of the merge landing.
Expand Down
2 changes: 1 addition & 1 deletion .license-overrides.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"@fortawesome/free-solid-svg-icons": "License is (CC-BY-4.0 AND MIT) — both are approved open-source licenses, compound AND expression not parsed by checker",
"smalot/pdfparser": "License is LGPL-3.0 — equivalent to LGPL-3.0-only which is on the allowlist, SPDX identifier variation not recognized by checker",
"apexcharts": "License is MIT — license-checker misreads logo URL as custom license, see https://github.com/apexcharts/apexcharts.js/blob/main/LICENSE",
"apexcharts": "NOT MIT. The last MIT release is 5.0.0 -- 5.1.0 onward is the ApexCharts dual-license (Community free only below USD 2M annual revenue; sublicensing under different terms not permitted). This app declares ^7.0.0. Conduction confirmed 2026-08-31 it is below USD 2M, so it qualifies for the Community tier. 🔴 UNRESOLVED: an OEM/Redistribution licence is separately required when embedding ApexCharts in a product used by other people, and is only waived for STATIC charts users cannot interact with -- RegisterDetail.vue and SchemaDetails.vue both set toolbar.show and zoom.enabled, and this app ships to third parties via the Nextcloud App Store. Escalated to the maintainers; do not read this override as a clearance for redistribution.",
"dompdf/dompdf": "License is LGPL-2.1 — equivalent to LGPL-2.1-or-later which is on the allowlist; configured hermetically (isRemoteEnabled=false / isPhpEnabled=false) at the single instantiation site PdfReportWriter:69"
}
86 changes: 81 additions & 5 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Open Register drijft apps zoals OpenCatalogi, Procest, Pipelinq en Software Cata

Vrij en open source onder de EUPL-licentie.
]]></description>
<version>2.0.12</version>
<version>2.0.15-unstable.20260905143606</version>
<licence>EUPL-1.2</licence>
<author mail="info@conduction.nl" homepage="https://www.conduction.nl/">Conduction</author>
<namespace>OpenRegister</namespace>
Expand Down Expand Up @@ -129,27 +129,26 @@ Vrij en open source onder de EUPL-licentie.
<job>OCA\OpenRegister\BackgroundJob\TransferCheckJob</job>
<job>OCA\OpenRegister\BackgroundJob\SyncConfigurationsJob</job>
<job>OCA\OpenRegister\BackgroundJob\SyncDataJob</job>
<job>OCA\OpenRegister\BackgroundJob\ScheduledWorkflowJob</job>
<job>OCA\OpenRegister\BackgroundJob\ScheduledNotificationJob</job>
<job>OCA\OpenRegister\BackgroundJob\ActionScheduleJob</job>
<job>OCA\OpenRegister\BackgroundJob\TenantDeprovisionJob</job>
<job>OCA\OpenRegister\BackgroundJob\TenantPurgeJob</job>
<job>OCA\OpenRegister\BackgroundJob\TenantUsageSyncJob</job>
<job>OCA\OpenRegister\BackgroundJob\ExecutionHistoryCleanupJob</job>
<job>OCA\OpenRegister\BackgroundJob\FlowRunRetentionJob</job>
<job>OCA\OpenRegister\BackgroundJob\AuditSealJob</job>
<job>OCA\OpenRegister\BackgroundJob\AvgRetentionJob</job>
<job>OCA\OpenRegister\BackgroundJob\DsarRetentionSweepJob</job>
<job>OCA\OpenRegister\BackgroundJob\ReportRenderJob</job>
<job>OCA\OpenRegister\BackgroundJob\NotificationQueueFlushJob</job>
<job>OCA\OpenRegister\BackgroundJob\TaskScheduledNotificationJob</job>
<job>OCA\OpenRegister\BackgroundJob\ArchivalRetentionTask</job>
<job>OCA\OpenRegister\BackgroundJob\FlowRunWorker</job>
<job>OCA\OpenRegister\BackgroundJob\FlowScheduleWorker</job>
<job>OCA\OpenRegister\BackgroundJob\FlowTimerWorker</job>
<job>OCA\OpenRegister\BackgroundJob\HandoffQueueDrainJob</job>
<job>OCA\OpenRegister\BackgroundJob\TemporalCalculationSweepJob</job>
<job>OCA\OpenRegister\BackgroundJob\DsarDpiaDetectionJob</job>
<job>OCA\OpenRegister\BackgroundJob\ScheduleReconcilerJob</job>
<job>OCA\OpenRegister\BackgroundJob\DbalIntrospectionJob</job>
<job>OCA\OpenRegister\BackgroundJob\OAuth2TokenRefreshJob</job>
<job>OCA\OpenRegister\BackgroundJob\ScheduledReportJob</job>
<job>OCA\OpenRegister\BackgroundJob\GroupReconcilerJob</job>
</background-jobs>
Expand Down Expand Up @@ -219,6 +218,27 @@ Vrij en open source onder de EUPL-licentie.
Copies the register-authored ones across, disabled, leaving the
register rows in place so the step stays reversible. -->
<step>OCA\OpenRegister\Repair\MigrateRegisterFlowsToTable</step>
<!-- CLEANS UP AFTER THE VERSION OF THE STEP ABOVE THAT DID NOT SCOPE
ITS READ. It asked findAll() for register `flows` / schema `flow`
at the TOP LEVEL of the config; ObjectService reads that pair
from `filters` and nowhere else, so both keys were inert and the
read ran against whatever register/schema the SHARED service was
still carrying. saveObject() sets that context and never restores
it, and ImportCredentialBrokerRegister saves two example objects
through it four steps earlier — so the migration copied both
`brokeredcredential` examples into openregister_flows: no nodes,
no edges, no trigger, owner `__system__`.

Post-migration ONLY. A fresh install runs the fixed migration,
which cannot produce these rows, so listing this under <install>
would be a guaranteed no-op.

Removes a row ONLY on the full conjunction: openregister-owned,
disabled, no nodes, no edges, no trigger/cron, never dispatched
(lastRun* null AND zero run rows), AND its uuid still resolves to
a register object whose schema is not `flow`. Anything ambiguous
is REPORTED by uuid, not deleted. Idempotent. -->
<step>OCA\OpenRegister\Repair\PurgePhantomMigratedFlows</step>
<step>OCA\OpenRegister\Repair\ImportTrustConfigurationRegister</step>
<step>OCA\OpenRegister\Repair\SeedVocabularyRegister</step>
<step>OCA\OpenRegister\Repair\RegisterOpenRegisterWithDoriath</step>
Expand All @@ -240,6 +260,42 @@ Vrij en open source onder de EUPL-licentie.
Post-migration, because it needs the flow_* columns the schema
migration adds. -->
<step>OCA\OpenRegister\Repair\RechainAuditTrailForFlowAttribution</step>
<!-- Task fixtures (flow-task-entity, ADR-001): the five seed
groups from the change's design.md, idempotent on uuid.
OPT-IN: runs only when app config openregister/seed_demo_tasks
is true, so a production instance never receives demo rows;
a demo instance and the test environment switch it on.
Post-migration because the step needs the openregister_tasks
tables its own change's migration creates. -->
<step>OCA\OpenRegister\Repair\SeedTaskFixtures</step>
<!-- Business timers (flow-business-timers, ADR-001): the flow-timers
register with its working-calendar and escalation-ladder schemas
and seeded defaults (nl-national, nl-termijn-default), idempotent
with force: false so administrator edits survive. Then the
invariant check, which COUNTS orphaned or inconsistent timers and
reports them rather than cancelling them. Post-migration because
both need the openregister_flow_timers tables. -->
<step>OCA\OpenRegister\Repair\SeedFlowTimerRegister</step>
<step>OCA\OpenRegister\Repair\CheckFlowTimerInvariants</step>
<!-- Approval consolidation (flow-approval-consolidation): moves
every approval chain, step set and in-flight decision onto
task sequences, verifies the reconciliation and FAILS LOUDLY
on any mismatch. Idempotent on the reconciliation columns.
Post-migration because it needs openregister_task_sequences
and the sequence columns on openregister_tasks. The legacy
tables are kept; rollback is the
openregister:approval:rollback-to-steps command. -->
<step>OCA\OpenRegister\Repair\MigrateApprovalChainsToTasks</step>
<step>OCA\OpenRegister\Repair\SeedCaseFixtures</step>
<!-- Business timers (flow-business-timers, ADR-001): the flow-timers
register with its working-calendar and escalation-ladder schemas
and seeded defaults (nl-national, nl-termijn-default), idempotent
with force: false so administrator edits survive. Then the
invariant check, which COUNTS orphaned or inconsistent timers and
reports them rather than cancelling them. Post-migration because
both need the openregister_flow_timers tables. -->
<step>OCA\OpenRegister\Repair\SeedFlowTimerRegister</step>
<step>OCA\OpenRegister\Repair\CheckFlowTimerInvariants</step>
</post-migration>
<install>
<step>OCA\OpenRegister\Repair\ReconcileDeclaredBackgroundJobs</step>
Expand Down Expand Up @@ -281,6 +337,7 @@ Vrij en open source onder de EUPL-licentie.
<step>OCA\OpenRegister\Repair\SeedVocabularyRegister</step>
<step>OCA\OpenRegister\Repair\RegisterOpenRegisterWithDoriath</step>
<step>OCA\OpenRegister\Repair\SeedZgwZakenMigrationPack</step>
<step>OCA\OpenRegister\Repair\SeedFlowTimerRegister</step>
</install>
</repair-steps>

Expand All @@ -295,6 +352,9 @@ Vrij en open source onder de EUPL-licentie.
<!-- App-rename repair: re-points registers and schemas at a new owning
app id. Only a DB connection, so the DI graph stays light. -->
<command>OCA\OpenRegister\Command\MigrateSchemaApplicationCommand</command>
<!-- The approval consolidation's reverse repair: an operator-run
rollback tool, deliberately NOT a repair step. -->
<command>OCA\OpenRegister\Command\RollbackApprovalMigrationCommand</command>
<command>OCA\OpenRegister\Command\RechainAuditTrailCommand</command>
<!-- Read-only report: which RBAC groups this instance declares, and whether
anyone belongs to them. Provisioning guarantees a declared group EXISTS;
Expand All @@ -310,8 +370,14 @@ Vrij en open source onder de EUPL-licentie.
<!-- field-level-object-encryption: encrypt existing plaintext values of a newly-flagged property. -->
<command>OCA\OpenRegister\Command\EncryptFieldCommand</command>
<command>OCA\OpenRegister\Command\DedupeRegistersCommand</command>
<command>OCA\OpenRegister\Command\AdoptLeafOrganisationsCommand</command>
<command>OCA\OpenRegister\Command\PruneRetiredSchemasCommand</command>
<command>OCA\OpenRegister\Command\RelinkRegisterSchemasCommand</command>
<command>OCA\OpenRegister\Command\ReconcileMagicTablesCommand</command>
<!-- The sanctioned administrative purge. Every HTTP delete route refuses an
archival record; this is the one path that can still destroy one, and it
needs shell access plus an explicit force flag. -->
<command>OCA\OpenRegister\Command\PurgeObjectCommand</command>
<command>OCA\OpenRegister\Command\DedupeConfigurationsCommand</command>
<command>OCA\OpenRegister\Command\ResolverListCommand</command>
<command>OCA\OpenRegister\Command\TimeReconcileCommand</command>
Expand Down Expand Up @@ -363,4 +429,14 @@ Vrij en open source onder de EUPL-licentie.
<contactsmenu>
<provider>OCA\OpenRegister\Contacts\ContactsMenuProvider</provider>
</contactsmenu>
<!-- The in-band write-back hook for projected task VTODOs
(flow-task-inbox-projections, design D-6). apps/dav's PluginManager
loads it into the Sabre server; it acts only on VTODOs carrying
X-OPENREGISTER-TASK and refuses an unauthorized edit with a DAV 403
before the client records it. -->
<sabre>
<plugins>
<plugin>OCA\OpenRegister\Dav\TaskVtodoWriteBackPlugin</plugin>
</plugins>
</sabre>
</info>
Loading
Loading