Skip to content

packs: check subcommand — the §6 enforcement lint (part of #270) - #486

Merged
apotema merged 2 commits into
mainfrom
packs/check-lint
Jul 1, 2026
Merged

apotema merged 2 commits into
mainfrom
packs/check-lint

Conversation

@apotema

@apotema apotema commented Jul 1, 2026 •

Copy link
Copy Markdown
Contributor

Adds labelle-assembler check --project-root <path> — the AST/token half of the Packs enforcement "net" (labelle-cli#270). The CLI companion PR (labelle-cli#packs/check-lint) delegates labelle check to this subcommand.

Part of the Packs initiative — umbrella labelle-toolkit/labelle-engine#651; RFC Flying-Platform/flying-platform-labelle docs/RFC-packs.md §6 "Enforcement — isolation is structural, not documented". This is the interim lint (the net) layer; the compile guarantees (module isolation + the PackView registry partition) land engine-side (#652-remainder).

Checks landed

# rule slug what it flags confidence
1 cross-pack-registry-access getType("<other>__X") / entityHasNamed(…, "<other>__X") on a foreign namespace prefix; view(.{ForeignComponent}) on an unambiguously foreign component high — anchored on the emitted <pack>__ name (#440); the string form is exactly the escape hole module isolation leaves open (§6-1b)
2 raw-global-facet-write direct Locked{…} construction in a pack that doesn't own the facet, bypassing Locked.tryAcquire high — Facet{ (construction) is distinct from Facet. (the sanctioned API); owner + own-name-clash guards avoid FPs
3 event-direction-inversion a lower pack referencing a higher pack's qualified event <higher>__<event>, per the depends_on DAG good, best-effort — reuses the DAG pack_validate.zig parses (#441); subscription detection is a qualified-name reference (it can't trace a subscription routed through an opaque value). The compile-time direction wall is future work, called out in the module doc-comment.

Precision was the priority — every rule errs toward silence over a false positive (ambiguous component owner → skip; qualified foo.Locked{} → skip; non-pack prefixes like engine__Position → skip).

Design

  • src/check.zig — pure, std-only token scanner over a Context (owner maps + DAG-derived "who is higher than me" set). 14 unit tests exercise each rule's positive + negative paths in-memory.
  • src/check_cmd.zig — the driver: reads project.labelle, discovers packs via plugin_manifest.loadPackFromDir, resolves dirs via cache.resolvePlugin, builds the owner maps + reverse-transitive depends_on closure, walks each pack's .zig files, prints file:line:col [rule] message, exits 1 on any finding (0 when clean / no packs). 2 fixture-based end-to-end tests (runLint) cover a violating three-pack tree and a clean one.
  • Wired into main.zig dispatch + usage; PROTOCOL_VERSION → 4 (informational — the CLI still only requires ≥3).

Verification

  • zig build ✓
  • zig build test ✓ — 46/46 steps, 1080/1084 passed (4 skipped, 0 failed); the new suites are check.zig (14) + check_cmd.zig (2 fixture).
  • zig fmt --check clean on all touched files.
  • Manual e2e against a synthetic three-pack game (contracts/citizens/production, production depends_on citizens): the violating tree reports all three rules and exits 1; the cleaned tree reports "no violations" and exits 0.

Deferred / honest limits

  • Rule 3's subscription detection is a qualified-name reference, not a full data-flow trace — precise on the packs: invisible <pack>__ namespacing + local→prefixed .jsonc rewrite (save-stable name) #440 emitted-name convention but not exhaustive. Documented in the check.zig module comment.
  • .global-facet derivation defaults to Locked (the RFC's canonical example) plus a contracts pack's own components; per-component .visibility isn't parsed yet (it doesn't exist in the manifest — see manifest.zig), so this is the pragmatic interim source.

Summary by CodeRabbit

  • New Features
    • Added a new check command to scan projects for Packs convention violations and report findings with precise file locations.
    • Expanded CLI help to document how to run labelle-assembler check --project-root <path>.
  • Bug Fixes
    • Improved validation coverage for cross-pack registry access, improper raw .global facet construction, and event-direction inversions.
    • Skips unreadable or malformed packs so checks complete even if some packs can’t be processed.

Add `labelle-assembler check --project-root <path>` — a static/token scan
over a game's packs that reports the Packs RFC §6 convention violations the
compile wall can't (yet) catch (the "net" layer of the enforcement stack).

Rules implemented:
  1. cross-pack registry access on foreign names — getType/entityHasNamed
     with a foreign `<other>__X` string, and view(.{ForeignComponent}) on an
     unambiguously foreign component (the string-escape hole, RFC §6-1b).
  2. raw `.global`-facet writes — direct `Locked{…}` construction in a
     non-owner pack, bypassing the sanctioned API (`Locked.tryAcquire`).
  3. event-direction inversions — a lower pack referencing a higher pack's
     qualified event (`<higher>__<event>`), using the depends_on DAG that
     pack_validate.zig already parses (#441). Subscription detection is
     heuristic (qualified-name reference); the compile-time wall is future.

`src/check.zig` is the pure, std-only token scanner (14 unit tests);
`src/check_cmd.zig` is the driver: discovers packs via `pack.labelle`,
builds the owner maps + reverse-transitive DAG, walks each pack's `.zig`
files, prints `file:line:col [rule] message`, exits 1 on any finding.
Fixture-based end-to-end tests cover a violating tree (all 3 rules) and a
clean tree. Protocol bumped to v4.

Part of the Packs initiative (umbrella labelle-engine#651; RFC
moca-tecnologia/flying-platform-labelle#561 §6).
@coderabbitai

coderabbitai Bot commented Jul 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new labelle check lint that scans Zig sources for Packs convention violations, a check_cmd.zig driver that discovers packs and builds cross-pack ownership data, and CLI wiring that adds the new subcommand and updates protocol/version help text.

Changes

Packs Enforcement Lint

Layer / File(s) Summary
Rule model and data types
src/check.zig
Defines Rule, Finding, Context, ownership structs, and helper routines for token decoding and foreign/owned symbol resolution.
Core scan logic and directory walk
src/check.zig
Implements the three lint checks, line/column emission, and recursive scanning of .zig files under a pack directory.
Scan rule unit tests
src/check.zig
Covers each rule’s positive and negative cases, plus the directory-walk integration case.
Pack discovery and shared context
src/check_cmd.zig
Defines pack/result containers, discovers pack manifests and registry stems, builds owner maps, and computes the dependents DAG.
Lint orchestration and reporting
src/check_cmd.zig
Implements runLint, CLI parsing and exit handling, reporting helpers, config loading, and end-to-end fixture tests.
CLI subcommand wiring
src/main.zig, src/root.zig
Adds the check import and dispatch, bumps protocol/version text, extends help output, and includes check code in test discovery.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Poem

I hopped through packs with twitchy nose,
and sniffed out lint from toe to toes.
Globals, events, and foreign rings—
all tidied up with bunny strings.
🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding the check subcommand for §6 enforcement linting.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch packs/check-lint

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/check_cmd.zig (1)

343-351: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated project.labelle reader.

The docstring itself flags this as a copy of main.zig's private helper. Two independent parsers for the same config format is a maintenance hazard — a future change to project.labelle parsing (e.g. new fields, error handling) risks drifting between the two copies.

Consider exporting the helper from main.zig (or hoisting it into config.zig) and having both call sites share it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/check_cmd.zig` around lines 343 - 351, The `readProjectConfig` helper in
`check_cmd.zig` is a duplicated parser for `project.labelle`, so replace this
inline copy with a shared implementation. Move or export the config-reading
logic from `main.zig` (or factor it into `config.zig`) and update
`readProjectConfig` and the existing `main.zig` call site to use the same
function so parsing, validation, and error handling stay in sync.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/check_cmd.zig`:
- Around line 113-124: The resolve failure in discoverPacks is being swallowed
by catch continue, which can hide skipped packs from the lint scan. Update the
cache.resolvePlugin path in discoverPacks to log a warning with std.log.warn
before continuing, matching the manifest.loadPackFromDir error handling and
including the plugin.name and error name so runLint/report can accurately
reflect partial scans.

In `@src/check.zig`:
- Around line 356-377: The raw global facet write check in scanSource is
overmatching function return types, since an identifier followed by “{” is being
treated as a facet construction even in signatures like fn currentLock() Locked
{ ... }. Update the logic in the scanSource path around the current facet-name
matching and period guard to recognize function declarations/return-type
contexts and skip those cases before calling emit for .raw_global_facet_write.
Add a regression test covering fn ...() Locked {} so the checker only flags
actual facet writes, not return types.

---

Nitpick comments:
In `@src/check_cmd.zig`:
- Around line 343-351: The `readProjectConfig` helper in `check_cmd.zig` is a
duplicated parser for `project.labelle`, so replace this inline copy with a
shared implementation. Move or export the config-reading logic from `main.zig`
(or factor it into `config.zig`) and update `readProjectConfig` and the existing
`main.zig` call site to use the same function so parsing, validation, and error
handling stay in sync.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7749083d-5494-496e-b22f-15ab02c82aff

📥 Commits

Reviewing files that changed from the base of the PR and between b2f0b8a and b653ce4.

📒 Files selected for processing (4)
  • src/check.zig
  • src/check_cmd.zig
  • src/main.zig
  • src/root.zig

Comment thread src/check_cmd.zig
Comment on lines +113 to +124
fn discoverPacks(arena: std.mem.Allocator, io: std.Io, cfg: ProjectConfig, root: []const u8) ![]const Pack {
var list: std.ArrayList(Pack) = .empty;
for (cfg.plugins) |plugin| {
const pack_dir = cache.resolvePlugin(arena, plugin, root) catch continue;
var manifest = (plugin_manifest.loadPackFromDir(arena, pack_dir, plugin.name) catch |err| {
// A malformed pack.labelle is a real problem, but the DAG gate
// (`pack_validate`) is where that's reported at generate time;
// the lint should not hard-fail on it. Skip and continue.
std.log.warn("labelle-assembler check: skipping pack '{s}': {s}", .{ plugin.name, @errorName(err) });
continue;
}) orelse continue; // not a pack (no pack.labelle)
defer manifest.deinit();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Resolve failures are silently dropped without logging — undermines lint reliability.

cache.resolvePlugin failures are swallowed via catch continue (line 116) with no log message, unlike the manifest-load failure a few lines below (117-123) which does std.log.warn. Since pack_count (line 108/152) only reflects successfully-resolved packs, a partial resolution failure silently shrinks the scanned set — runLint never surfaces it, and report() will print "no violations found" for packs that were never actually scanned. For an enforcement lint whose whole purpose is a CI gate, silently skipping a pack defeats the tool's guarantee: a broken/unresolvable pack passes the check instead of failing loudly.

🛡️ Proposed fix — log the resolve failure like the manifest-load path does
     for (cfg.plugins) |plugin| {
-        const pack_dir = cache.resolvePlugin(arena, plugin, root) catch continue;
+        const pack_dir = cache.resolvePlugin(arena, plugin, root) catch |err| {
+            std.log.warn("labelle-assembler check: skipping pack '{s}': failed to resolve ({s})", .{ plugin.name, `@errorName`(err) });
+            continue;
+        };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn discoverPacks(arena: std.mem.Allocator, io: std.Io, cfg: ProjectConfig, root: []const u8) ![]const Pack {
var list: std.ArrayList(Pack) = .empty;
for (cfg.plugins) |plugin| {
const pack_dir = cache.resolvePlugin(arena, plugin, root) catch continue;
var manifest = (plugin_manifest.loadPackFromDir(arena, pack_dir, plugin.name) catch |err| {
// A malformed pack.labelle is a real problem, but the DAG gate
// (`pack_validate`) is where that's reported at generate time;
// the lint should not hard-fail on it. Skip and continue.
std.log.warn("labelle-assembler check: skipping pack '{s}': {s}", .{ plugin.name, @errorName(err) });
continue;
}) orelse continue; // not a pack (no pack.labelle)
defer manifest.deinit();
fn discoverPacks(arena: std.mem.Allocator, io: std.Io, cfg: ProjectConfig, root: []const u8) ![]const Pack {
var list: std.ArrayList(Pack) = .empty;
for (cfg.plugins) |plugin| {
const pack_dir = cache.resolvePlugin(arena, plugin, root) catch |err| {
std.log.warn("labelle-assembler check: skipping pack '{s}': failed to resolve ({s})", .{ plugin.name, `@errorName`(err) });
continue;
};
var manifest = (plugin_manifest.loadPackFromDir(arena, pack_dir, plugin.name) catch |err| {
// A malformed pack.labelle is a real problem, but the DAG gate
// (`pack_validate`) is where that's reported at generate time;
// the lint should not hard-fail on it. Skip and continue.
std.log.warn("labelle-assembler check: skipping pack '{s}': {s}", .{ plugin.name, `@errorName`(err) });
continue;
}) orelse continue; // not a pack (no pack.labelle)
defer manifest.deinit();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/check_cmd.zig` around lines 113 - 124, The resolve failure in
discoverPacks is being swallowed by catch continue, which can hide skipped packs
from the lint scan. Update the cache.resolvePlugin path in discoverPacks to log
a warning with std.log.warn before continuing, matching the
manifest.loadPackFromDir error handling and including the plugin.name and error
name so runLint/report can accurately reflect partial scans.

Comment thread src/check.zig
Comment on lines +356 to +377
for (ctx.global_facets) |gf| {
if (!std.mem.eql(u8, gf.name, name)) continue;
// The owner may construct its own facet freely.
if (gf.owner_prefix) |op| {
if (std.mem.eql(u8, op, ctx.current_prefix)) return;
}
// A pack that defines its OWN type of this name isn't touching the
// shared facet — skip to avoid a false positive on a name clash.
if (currentOwnsComponent(name, ctx)) return;
// Qualified (`foo.Locked{}`) is a field/namespaced access we can't
// confidently attribute to the facet — stay silent for precision.
if (ident_i > 0 and toks[ident_i - 1].tag == .period) return;

const msg = try std.fmt.allocPrint(
arena,
"pack '{s}' constructs the shared '.global' facet '{s}' directly (`{s}{{...}}`); global facets are multi-writer coordination primitives and must be mutated via their sanctioned API (e.g. `{s}.tryAcquire`), never a raw component write (RFC §6)",
.{ ctx.current_prefix, name, name, name },
);
try emit(arena, findings, .raw_global_facet_write, src, file, toks[ident_i].start, msg);
return;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Look for consumer-side functions returning a candidate global facet type (e.g. Locked)
# to gauge how often the return-type shape occurs in real pack sources.
rg -nP '\)\s*Locked\s*\{' -g '*.zig'

Repository: labelle-toolkit/labelle-assembler

Length of output: 171


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the rule implementation and nearby helpers.
sed -n '320,390p' src/check.zig

# Find any parsing/token-context helpers that distinguish struct literals from type positions.
rg -n "currentOwnsComponent|global_facets|ident_i|tag == \\.period|\\.l_brace|\\.identifier|function|return type|type position" src/check.zig

Repository: labelle-toolkit/labelle-assembler

Length of output: 4204


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect where checkGlobalFacetWrite is called and what token pattern it sees.
sed -n '220,320p' src/check.zig
sed -n '390,470p' src/check.zig

# Show the existing tests around the global facet rule.
sed -n '580,730p' src/check.zig

# Look for any parsing helpers that would exclude function signatures/return types.
rg -n "fn .*checkGlobalFacetWrite|raw_global_facet_write|function declaration|return type|fn currentLock|\\.fn" src/check.zig

Repository: labelle-toolkit/labelle-assembler

Length of output: 12656


<name>{ should not flag function return types

scanSource treats any identifier followed by { as a facet write, so fn currentLock() Locked { ... } is reported even though Locked is only the return type. The current . guard only skips qualified names, so this still needs a bit more context disambiguation plus a regression test for fn ...() Locked {}.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/check.zig` around lines 356 - 377, The raw global facet write check in
scanSource is overmatching function return types, since an identifier followed
by “{” is being treated as a facet construction even in signatures like fn
currentLock() Locked { ... }. Update the logic in the scanSource path around the
current facet-name matching and period guard to recognize function
declarations/return-type contexts and skip those cases before calling emit for
.raw_global_facet_write. Add a regression test covering fn ...() Locked {} so
the checker only flags actual facet writes, not return types.

…col 5

Both #485 (add, protocol 4) and this PR (#440/#270 check) added a subcommand +
protocol bump. Resolved: keep both subcommand imports/usage/dispatch/tests;
add is v4, check is now v5. (The naive union left the check/add dispatch ifs
sharing one closing brace — fixed to two separate blocks.)
@apotema

apotema commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
src/main.zig (1)

40-47: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Version-history comments are out of order.

The v5 block (lines 40-43, check) is listed before the v4 block (lines 44-46, add), even though PROTOCOL_VERSION is bumped to 5 here. Reading top-to-bottom now gives v2, v3, v5, v4 — confusing for anyone adding v6 later.

✏️ Suggested reorder
-/// v5 (labelle-cli#270): added the `check` subcommand — the Packs
-/// enforcement lint (RFC §6). Additive; the CLI's `labelle check` delegates
-/// to it. The CLI still only *requires* protocol >= 3 (older binaries just
-/// lack `check`), so this bump is informational.
 /// v4 (Packs `#271`): added the `add` subcommand (`add pack <name>` /
 /// `add feature <kind> <name>`). The CLI delegates pack/feature-unit
 /// scaffolding to the binary.
+///
+/// v5 (labelle-cli#270): added the `check` subcommand — the Packs
+/// enforcement lint (RFC §6). Additive; the CLI's `labelle check` delegates
+/// to it. The CLI still only *requires* protocol >= 3 (older binaries just
+/// lack `check`), so this bump is informational.
 pub const PROTOCOL_VERSION: u32 = 5;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main.zig` around lines 40 - 47, The version-history comments above
PROTOCOL_VERSION are out of chronological order, with the v5 note appearing
before v4; reorder the adjacent comment blocks in src/main.zig so they read in
ascending version order (older to newer) while keeping the PROTOCOL_VERSION
constant and the existing descriptions intact, using the PROTOCOL_VERSION symbol
as the anchor.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/main.zig`:
- Around line 40-47: The version-history comments above PROTOCOL_VERSION are out
of chronological order, with the v5 note appearing before v4; reorder the
adjacent comment blocks in src/main.zig so they read in ascending version order
(older to newer) while keeping the PROTOCOL_VERSION constant and the existing
descriptions intact, using the PROTOCOL_VERSION symbol as the anchor.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5de9db94-1d63-4508-a280-fb72baa4b73c

📥 Commits

Reviewing files that changed from the base of the PR and between b653ce4 and 86f09fa.

📒 Files selected for processing (1)
  • src/main.zig

@apotema
apotema requested a review from Copilot July 1, 2026 18:57
@apotema

apotema commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@apotema
apotema merged commit a3b5826 into main Jul 1, 2026
5 checks passed

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

Adds a new labelle-assembler check --project-root <path> subcommand that lints Packs §6 “enforcement net” violations by scanning pack source tokens and reporting rule-based findings with file/line/col, integrating it into the CLI dispatch and protocol versioning.

Changes:

  • Introduces a check.zig token-scanner implementing three enforcement rules (cross-pack registry access, raw .global facet writes, event direction inversions) with unit tests.
  • Adds check_cmd.zig driver to discover packs from project.labelle, build shared ownership/DAG context, run scans over pack directories, and report/exit non-zero on violations (with fixture e2e tests).
  • Wires the check subcommand into main.zig usage/dispatch and updates protocol versioning.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/root.zig Ensures the new check.zig module is included in the test import set.
src/main.zig Adds check to usage + dispatch and bumps PROTOCOL_VERSION.
src/check.zig Implements the pure token-scan lint rules and pack directory walker, with unit tests.
src/check_cmd.zig Implements pack discovery/context building, reporting, and end-to-end fixture tests for check.

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

Comment thread src/check.zig
Comment on lines +289 to +292

// Rule 3 — reference to a higher pack's qualified event.
try checkEventDirection(arena, findings, src, file, ctx, tk, name);
}
Comment thread src/main.zig
Comment on lines +40 to +47
/// v5 (labelle-cli#270): added the `check` subcommand — the Packs
/// enforcement lint (RFC §6). Additive; the CLI's `labelle check` delegates
/// to it. The CLI still only *requires* protocol >= 3 (older binaries just
/// lack `check`), so this bump is informational.
/// v4 (Packs #271): added the `add` subcommand (`add pack <name>` /
/// `add feature <kind> <name>`). The CLI delegates pack/feature-unit
/// scaffolding to the binary.
pub const PROTOCOL_VERSION: u32 = 4;
pub const PROTOCOL_VERSION: u32 = 5;
Comment thread src/check.zig
Comment on lines +452 to +453
while (try it.next(io)) |entry| {
const child = try std.fs.path.join(arena, &.{ dir_path, entry.name });
Comment thread src/check_cmd.zig
Comment on lines +278 to +286
for (packs, 0..) |_, x| {
const visited = try arena.alloc(bool, n);
@memset(visited, false);
try dfsReach(arena, packs, &index_of, x, visited);
for (0..n) |r| {
if (r == x) continue;
if (visited[r]) try accum[r].append(arena, packs[x].prefix);
}
}
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