Skip to content

Multiple fixes for broken master#26

Open
line0 wants to merge 141 commits into
masterfrom
add-missing-semver-module
Open

Multiple fixes for broken master#26
line0 wants to merge 141 commits into
masterfrom
add-missing-semver-module

Conversation

@line0

@line0 line0 commented May 23, 2026

Copy link
Copy Markdown
Contributor

This PR fixes several issues, largely caused by the incomplete refactoring some 10 years ago:

  • SemanticVersioning: this class was missing entirely and has been ported over from the sqlite branch
  • ModuleLoader: Fixed a regression where __depCtrlInit hooks were called again on - already-initialized modules, causing errors in modules that mutate their exported state on - first call (e.g., BadMutex).,
  • UpdateFeed: Fixed a regression where legacy boolean true/false script type arguments were - no longer accepted after the ScriptType enum migration.,
  • UpdateFeed: Fixed a regression where DownloadManager was instantiated too late, causing the - update process to fail.
  • Common: The capitalize() function no longer uses unsupported string indexing and now works - for the first time ever. Before the refactor, this was previously masked by it not actually - being called anywhere.
  • Updater: Fixed a potential issue where a multi-assignment statement could corrupt record - fields after an unsuccessful update.

Additionally, i have added a unit test suite for DepCtrl (only 1 tiny test for now) and made all files use LF + EOF Newline to ensure consistent file hashes.

Copilot AI 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.

Pull request overview

This PR aims to restore a working “master” by reintroducing missing version-handling functionality, fixing several regressions in module loading and update/feed handling, and adding initial unit-test and line-ending consistency infrastructure.

Changes:

  • Added SemanticVersioning and migrated version parsing/formatting to use it across updater/feed paths.
  • Fixed/adjusted updater + module-loader behaviors related to initialization and update flows, and added a minimal DepCtrl unit test.
  • Updated the project update feed metadata, bumped versions, and enforced LF + final newline consistency.

Reviewed changes

Copilot reviewed 12 out of 15 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
modules/DependencyControl/Updater.moon Migrates updater version handling to SemanticVersioning and adjusts update logging/changelog display.
modules/DependencyControl/UpdateFeed.moon Adds legacy scriptType compatibility + new invalid scriptType messaging; moves DownloadManager init earlier.
modules/DependencyControl/UnitTestSuite.moon No functional change (newline normalization).
modules/DependencyControl/Tests.moon Adds a first unit test for Common.terms.capitalize.
modules/DependencyControl/SemanticVersioning.moon Introduces semantic version parsing/formatting/comparison utilities.
modules/DependencyControl/Record.moon Switches record version parsing to SemanticVersioning and adds compatibility helpers.
modules/DependencyControl/ModuleLoader.moon Updates init-hook guard logic and switches version formatting/parsing to SemanticVersioning.
modules/DependencyControl/FileOps.moon No functional change (newline normalization).
modules/DependencyControl/ConfigHandler.moon No functional change (newline normalization).
modules/DependencyControl/Common.moon Fixes capitalize() implementation to avoid unsupported string indexing.
modules/DependencyControl.moon Bumps DepCtrl version, exposes SemanticVersioning, and adds a Moonscript minimum-version guard.
macros/l0.DependencyControl.Toolbox.moon Bumps toolbox version; updates version formatting and script-type handling; registers DepCtrl test suite.
DependencyControl.json Updates feed versions/hashes and adds new files (including tests) to the module feed.
.vscode/settings.json Enforces final newline on save in VS Code.
.gitattributes Enforces LF line endings in git.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread modules/DependencyControl/UpdateFeed.moon Outdated
Comment thread modules/DependencyControl/UpdateFeed.moon Outdated
Comment thread modules/l0/DependencyControl/SemanticVersioning.moon Outdated
Comment thread modules/l0/DependencyControl/SemanticVersion.moon
Comment thread modules/DependencyControl/Updater.moon Outdated
Comment thread modules/l0/DependencyControl/ModuleLoader.moon
Comment thread modules/DependencyControl/ModuleLoader.moon Outdated
Comment thread DependencyControl.json Outdated
@line0
line0 force-pushed the add-missing-semver-module branch 2 times, most recently from 7f7ad69 to 9fee44a Compare May 23, 2026 22:10
@line0
line0 requested a review from Copilot May 23, 2026 22:10

Copilot AI 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.

Pull request overview

Copilot reviewed 12 out of 15 changed files in this pull request and generated 5 comments.

Comment thread modules/DependencyControl/Updater.moon Outdated
Comment thread modules/DependencyControl/ModuleLoader.moon Outdated
Comment thread macros/l0.DependencyControl.Toolbox.moon Outdated
Comment thread macros/l0.DependencyControl.Toolbox.moon Outdated
Comment thread modules/DependencyControl/SemanticVersioning.moon Outdated
@line0
line0 force-pushed the add-missing-semver-module branch from 9fee44a to ad4a5ec Compare May 23, 2026 22:46
@line0
line0 requested a review from Copilot May 23, 2026 22:49

Copilot AI 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.

Pull request overview

Copilot reviewed 12 out of 15 changed files in this pull request and generated 5 comments.

Comment thread modules/DependencyControl/ModuleLoader.moon Outdated
Comment thread modules/DependencyControl/ModuleLoader.moon Outdated
Comment thread modules/l0/DependencyControl/ModuleLoader.moon Outdated
Comment on lines 57 to 64
maxVer = SemanticVersioning\toNumber @version
minVer = SemanticVersioning\toNumber minVer

changelog = {}
for ver, entry in pairs @changelog
ver = DependencyControl\parseVersion ver
verStr = DependencyControl\getVersionString ver
ver = SemanticVersioning\toNumber ver
verStr = SemanticVersioning\toString ver
if ver >= minVer and ver <= maxVer
Comment thread modules/l0/DependencyControl/Updater.moon Outdated
@line0
line0 force-pushed the add-missing-semver-module branch from ad4a5ec to 5bc3f45 Compare May 23, 2026 23:14
line0 added 4 commits May 24, 2026 08:14
nothing inside DepCtrl is supplying this parameter, so the only effect
this bug would have had, is removing the default guard against modules
trying to load themselves
- assert now passes through all varargs on success (allows chaining)
- new assertNotNil method - fails only on nil, unlike assert which also fails on false
- dump/dumpToString methods accept a maxDepth to cap recursive table output
- new static Logger.describeType method - returns Lua type name but renders MoonScript class instances as "ClassName object"
- fix: guard log/format calls against non-string message templates
line0 and others added 25 commits July 17, 2026 01:56
Mechanical rename of the module, its test suite, and all ~180 references
ahead of making the class instantiable as a version value. No behavior
change. Safe because the class was only split out during the (unreleased)
0.7.0 refactor, so there is no external API to keep compatible.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… bumping

Construct a version from a string or numeric components (or via fromPacked);
instances compare with </<=/==, stringify, bump immutably, and satisfy ranges.
The static helpers accept an instance anywhere they take a version, and the
static formerly named toNumber is renamed toPacked to match the instance method.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A new primitive for declaring get/set computed properties on a class:
Accessors.property{get, set} marks a property in the class body and
Accessors.install(class) — called once after the body — rewrites the
instance metatable so reads/writes of those keys dispatch to the getter/
setter, falling through to normal method/field lookup otherwise. A
setter-less property is read-only (a write raises); a subclass that runs
install inherits its parent's properties; every property is recorded on
class.__accessors for inspection tooling. Centralizes the metatable
manipulation in one audited place.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A record's canonical version is now a SemanticVersion value object stored as
@semanticVersion, with record.version a packed-integer accessor over it, so
existing packed-int reads/writes/comparisons are unchanged. The version is
persisted to the config as a "major.minor.patch" string (readable at a glance),
migrated from the old packed-integer form on first load; @semanticVersion is
initialized up front so a record exposed mid-construction never reads a nil.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
install adds a __pairs metamethod so a readable computed property appears in
pairs(instance) with its getter value, like a raw field (under 52compat). Since
version then shows up as a packed int while the config stores a string, it's
kept out of Record's generic scriptFields copy and serialized explicitly.
Inline comments across the rework are tightened per the guidelines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contribution conventions for DependencyControl: annotation/comment style,
file naming, MoonScript gotchas, the public-API and test-exposure patterns,
computed properties via Accessors, module-private markers, and changelog rules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "build macro and module lists" and "create and run the update tasks"
comments only restated the immediately following buildDlgList /
buildInstalledDlgList / runUpdaterTask calls, which the variable names
already convey.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Convert getProgress -> progress (Downloader), getState -> state (Lock),
getFailures -> failures (UnitTestSuite) and isPrivate (Host) from methods into
read-only computed properties via the Accessors module, updating their call
sites: the DownloadManager shim, the depctrl CLI runner, and the tests.
Host.isPrivate memoizes into a backing field so repeated reads (and pairs) stay
cheap after the one-time resolution.

Add LockState/LockScope LuaCATS aliases so the enum-typed field and returns carry
named types instead of a bare integer/string with a prose hint, and refresh the
now-stale getFailures example in AGENTS.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…overy

- Revert fileBaseUrl/localFileBasePath to plain strings (the
  object-valued fileBaseUrl broke v0.3.0 consumers like the DepCtrl
  browser) and add fileBaseUrls/localFileBasePaths: per-file-type maps
  of full URL/path templates that collapse into the effective
  @{fileBaseUrl}/@{localFileBasePath} at each file record, with the
  scalars as fallback. The maps roll from any level; DepCtrl's own feed
  keeps its dotted macro layout via a macros section override.
- Add @{scriptType}/@{scriptTypeSection}, plus author-defined variables
  (root-level vars object) with computed-key lookups —
  @{tagSuffix:@{channel}} derives the per-channel release-tag suffix.
  Expansion is now brace-aware and runs to a bounded fixpoint.
- Add update-feed --add-files (UpdateFeed.findUnlistedFiles): invert
  the effective localFileBasePaths templates, scan the trees beneath,
  and append complete entries for unlisted files, attributing types by
  longest template prefix. Its first run found six unshipped 0.7.0
  files (Accessors, FeedLoader, config-schema + test suites), now in
  the feed.
- Fix update-feed --dry-run writing the feed anyway (`dry_run and false
  or nil` collapses to nil, i.e. "write").
- Promote the recursive file lister to FileOps.listFilesRecursive.
- Update the v0.4.0 schema, document the template machinery and the
  update-feed command in the README, and add unit coverage for
  expansion, discovery, and the addFiles flow.
- FileOps: mkdir/rmdir now treat only an explicit error (or an
  unchanged directory state) as failure. Aegisub's bundled lfs returns
  nothing on success where LuaFileSystem returns true, so the stricter
  success check introduced this cycle failed every install inside
  Aegisub with "failed to create temporary download directory
  (unknown error)".
- Record: uninstall escapes namespace-derived Lua patterns (new
  Common.escapePattern helper) and anchors them on both sides, so
  uninstalling a module no longer sweeps a prefix-sharing sibling
  package (l0.Functional vs l0.FunctionalExtras) into the recursive
  delete, and hyphenated namespaces no longer match unrelated files.
- UpdateTask: install/update messages no longer render "Starting nil
  of ..." — Common.terms.isInstall is keyed by true/false, but
  installed records leave `virtual` nil (new getInstallTerm helper).
- test.moon: pass basePath to the Record test class; its chunk took no
  arguments, so basePath silently resolved to a nil global.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… logging

- Logger: the window sink no longer repeats the indent prefix on chunks
  that continue the logger's own open line, so incremental output like
  the download progress bar renders as one clean bar. The file sink
  already guarded this via its line-header check; the window sink now
  uses the existing stream-ownership state the same way.
- Toolbox: the startup update sweep relays structured updater statuses
  (deliberate refusals like unmanaged records, or already-reported run
  results) verbatim at trace level instead of framing them as
  "Unexpected error scheduling update"; that framing now only applies
  to the pcall branch that catches an actual raise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…g entries

- SemanticVersion: route every toString input through toPacked, so nil
  renders as "0.0.0" and SemanticVersion instances convert instead of
  both crashing in bit.rshift; a malformed string still returns
  nil, err.
- Toolbox: buildInstalledDlgList treats config entries as the arbitrary
  on-disk data they are — a missing name falls back to the namespace
  and an unrenderable version to "?", so orphaned/unmanaged entries get
  a selectable row instead of erroring the whole picker.
- Toolbox: hoist the per-insert table.sort out of both dialog-list
  build loops.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…path

- assertItemsEqual/assertItemsAre: use the (previously dead) itemsEqual
  failure template with an "equal"/"identical" qualifier — the keys
  sub-phrase was being passed as the whole message — and type-check the
  `expected` argument instead of checking `actual` twice.
- assertContinuous: check integer *keys* for continuity; it counted
  integer values, failing continuous tables of strings and passing
  sparse ones.
- assertNotAlmostEquals: report through its own (existing but unused)
  notAlmostEquals template instead of the assertAlmostEquals text.
- assertError: stop counting the pcall status flag among a non-raising
  function's returned values.
- UnitTestSetup: initialize @stubs so ut\stub works inside a _setup.
  Setup stubs are class-scoped: alive through every test and the
  teardown, restored when the class finishes (immediately on a failed
  setup).
- Suite run(true): the abort path now stamps @endTime/@success (fixing
  missing CTRF timings) and logs through msgs.run.aborted — the key it
  referenced didn't exist, so the Logger silently swallowed it.
- Test harness: the silence() helper's no-op logEx now raises on
  level 1 like the real logger — that raise is the mechanism by which
  a failing assertion fails its test, so silenced suites could never
  report failure. The probe and no-op loggers also gained dumpToString,
  which every assert evaluates eagerly even when passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…me collision

- Record.init: the `logsHaveBeenTrimmed` local was written but never read, and
  init already runs once per Lua state, so trimFiles now runs unconditionally.
- UpdateTask.performUpdate: remove the unreachable `@running` guard. Its only
  caller run() already guards, and firing it here would route through `finish`
  and clobber the running invocation's state.
- Record: rename the static `loadConfig` to `loadGlobalConfig` so it can no
  longer be silently confused with the instance `loadConfig` of the same name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The install/uninstall/update pickers each built a sorted display list and its
item→record map with the same append-then-sort boilerplate, differing only in
how they enumerate their rows. Extract that into `sortedDlgList`, which takes an
`add item, record` callback, so `buildInstalledDlgList` and `buildDlgList` supply
only their row enumeration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…elpers

The test files each built their own `setmetatable {…}, __index: Class.__base`
stub selves, no-op loggers, and seeded FeedTrust stubs — seven near-identical
factories in test/UpdateTask.moon alone, with more copies in the Updater,
FeedTrust, UpdateFeed, and Record tests. Add test/helpers/stub-helpers with
`stubSelf`, `makeNullLogger`, and `makeSeededFeedTrust`, and route all five
files through them so the fakes stop drifting. `makeNullLogger`'s assert
passes its condition through (and never raises), so assert-guarded code such
as Updater.require keeps working against it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Section defaults were served by two mechanisms: copy-on-write proxies wrapping
each top-level default section (the first write into an absent section
materialized the whole section's defaults into the user config) and the
per-key mergeSection fallthrough for sections already present. Serve both
cases through mergeSection: it now binds to the view's live userConfig and
section key, so a held section view survives a refresh or load replacing that
table, and a first write into an absent section creates it sparsely with just
the written key — defaults are never materialized into stored config.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…perty

Each feed instance replaced its metatable with a fresh closure table just to
synthesize `url` from `_url` or the local file name, allocating a metatable per
feed and breaking `getmetatable(feed) == UpdateFeed.__base` identity. Declare
`url` as a read-only Accessors computed property instead: reads behave as
before, instances keep the shared class metatable, and a write to `url` (which
previously shadowed the synthesized value via rawset) now raises.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The loading methods disagreed on their failure shape: fetch and loadFile
returned false plus an error, ensureLoaded returned either nil or false
depending on the failing leg, and even UpdateFeed's own wrappers handled the
result inconsistently. All three now return nil plus the error message.
getScript's false is untouched: it distinguishes "not in this feed" (false, no
error) from a real failure (nil, err), and checkFeed relies on that. The
constructor keeps its documented raise — a MoonScript constructor's return
value is discarded, so it cannot report nil, err.

fetch's failure value shipped as false in 0.6.3; every known caller checks
truthiness, so the change is noted in the changelog rather than kept as a
permanent inconsistency in the frozen API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… flow; isolate ManageFeeds from the network

The ManageFeeds tests drove the real offline gather against the live trust
singleton, whose official-set load fetches the DepCtrl feed over the network on
a cold cache — a class setup now seeds both official accessors so no test run
leaves the process. New coverage: the startup sweep (per-record scheduling,
module test-menu registration, tolerance of a raising or refusing
scheduleUpdate, lock release) via scheduleUpdatesAndRegisterTests moving above
registerMacros to join the test exports; the uninstall result shapes (success,
string error, per-file error table, locked files) through a construction seam
that swaps the class __call in a setup/teardown pair, since LuaJIT requires a
metamethod to be a plain function and a Stub cannot stand in; and the Manage
Feeds Block flow (reason prompt travels in the action options, declining the
sourced-packages warning abandons the block).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…states

Replicates Aegisub loading one DependencyControl copy per automation script in
isolated Lua environments at the same time — the scenario the Logger's seed
sleep exists for. Overlapping luajit child processes each seed through the real
Logger construction and report the head of their random stream, which must be
unique per state; self-gates where a child process can't be spawned.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
First Logger construction slept half a second (10ms x 50) per Lua state purely
to spread math.randomseed apart across simultaneously loading scripts — the
single largest avoidable startup cost DependencyControl added to every script.
The monotonic clock's sub-microsecond reading already diverges per state, and
adding the pid separates whole processes, so the seed needs no waiting at all;
the per-state Timer instance existed only for this and is gone too. The
LoggerIntegration guard proves the divergence property across overlapping
isolated states with the sleep removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@line0
line0 force-pushed the add-missing-semver-module branch from f877e92 to bab4f69 Compare July 18, 2026 00:03
@line0
line0 force-pushed the add-missing-semver-module branch from bab4f69 to c985d61 Compare July 18, 2026 01:09
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