From 3632f9e77701c471663f1118f1899f881adf0fa4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 18 Jul 2026 16:18:44 +0000 Subject: [PATCH 1/9] Add aps CLI that dogfoods AppState outside SwiftUI Ship a Swift 6 ArgumentParser executable with get/set/watch/dump over a fixed demo schema (State, StoredState, FileState) and real @AppDependency injection for clock + JSON coding. Co-authored-by: Leif --- .gitignore | 11 +++ Package.resolved | 33 +++++++ Package.swift | 34 +++++++ README.md | 102 ++++++++++++++++++++- Sources/aps/Aps.swift | 115 +++++++++++++++++++++++ Sources/aps/DemoKey.swift | 46 ++++++++++ Sources/aps/DemoState.swift | 56 ++++++++++++ Sources/aps/Dependencies.swift | 36 ++++++++ Sources/aps/StateStore.swift | 161 +++++++++++++++++++++++++++++++++ Tests/apsTests/APSTests.swift | 104 +++++++++++++++++++++ 10 files changed, 696 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 Package.resolved create mode 100644 Package.swift create mode 100644 Sources/aps/Aps.swift create mode 100644 Sources/aps/DemoKey.swift create mode 100644 Sources/aps/DemoState.swift create mode 100644 Sources/aps/Dependencies.swift create mode 100644 Sources/aps/StateStore.swift create mode 100644 Tests/apsTests/APSTests.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f24f582 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.DS_Store +/.build +/.swiftpm +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc +*.swp +*~ diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..810ca4c --- /dev/null +++ b/Package.resolved @@ -0,0 +1,33 @@ +{ + "originHash" : "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", + "pins" : [ + { + "identity" : "appstate", + "kind" : "remoteSourceControl", + "location" : "https://github.com/0xLeif/AppState", + "state" : { + "revision" : "5053feab3497605386613e4309bc0cf8c95dc5c4", + "version" : "3.0.1" + } + }, + { + "identity" : "cache", + "kind" : "remoteSourceControl", + "location" : "https://github.com/0xLeif/Cache", + "state" : { + "revision" : "a959a473d81da9aeb17dac7c050f0a07775f2c18", + "version" : "2.1.3" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser", + "state" : { + "revision" : "6a52f3251125d74daf04fcbd5e6f08a75d074382", + "version" : "1.8.2" + } + } + ], + "version" : 3 +} diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..c8a46e8 --- /dev/null +++ b/Package.swift @@ -0,0 +1,34 @@ +// swift-tools-version: 6.0 + +import PackageDescription + +let package = Package( + name: "aps", + platforms: [ + .macOS(.v14) + ], + products: [ + .executable( + name: "aps", + targets: ["aps"] + ) + ], + dependencies: [ + .package(url: "https://github.com/0xLeif/AppState", from: "3.0.0"), + .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0") + ], + targets: [ + .executableTarget( + name: "aps", + dependencies: [ + .product(name: "AppState", package: "AppState"), + .product(name: "ArgumentParser", package: "swift-argument-parser") + ] + ), + .testTarget( + name: "apsTests", + dependencies: ["aps"] + ) + ], + swiftLanguageModes: [.v6] +) diff --git a/README.md b/README.md index 897f8bd..4fc4f45 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,100 @@ -# aps-cli -📀 AppState CLI +# aps + +A tiny Swift CLI that [dogfoods](https://github.com/0xLeif/AppState) **AppState** outside SwiftUI: declare typed app state, get/set/watch/dump it, and show dependency injection. + +Cross-platform where AppState allows — **macOS** and **Linux** first. + +## Commands + +```text +aps get +aps set +aps watch # print on change (Observation + polling) +aps dump # print all known state as JSON +aps --help +``` + +### Demo keys (fixed schema) + +| Key | Type | Storage | Lifetime | +| --- | --- | --- | --- | +| `counter` | `Int` | `State` | Process (in-memory) | +| `message` | `String` | `State` | Process (in-memory) | +| `flag` | `Bool` | `StoredState` | Persisted (`UserDefaults`; CLI calls `synchronize()` so Linux flushes) | +| `note` | `String` | `FileState` | Persisted (`~/.aps/note.json`) | + +Dynamic / user-declared keys are intentionally out of scope for v1. + +### Dependencies + +`aps` injects real services with `@AppDependency` / `Application.dependency`: + +- **`clock`** — wall clock for dump timestamps +- **`jsonCoding`** — shared `JSONEncoder` helpers for `aps dump` + +## Requirements + +- Swift 6.0+ +- macOS 14+ or Linux (Swift.org toolchain) + +## Build & run + +```bash +git clone https://github.com/0xLeif/aps-cli.git +cd aps-cli +swift build +swift run aps --help +``` + +Release build: + +```bash +swift build -c release +.build/release/aps dump +``` + +### Examples + +```bash +# In-memory State +swift run aps set counter 3 +swift run aps get counter +swift run aps set message "hello from aps" + +# Persisted StoredState / FileState +swift run aps set flag true +swift run aps set note "saved across launches" +swift run aps get note + +# Inspect everything (uses injected JSONCoding + clock) +swift run aps dump + +# Watch for changes (Ctrl+C to stop) +swift run aps watch note --interval 200 +``` + +`watch` uses Swift Observation for in-process updates and polls as a fallback so disk-backed `FileState` / `StoredState` changes can still surface. + +## Tests + +```bash +swift test +``` + +## Layout + +```text +Package.swift +Sources/aps/ # executable + AppState demo surface +Tests/apsTests/ # parsing + state round-trips +``` + +## Non-goals (v1) + +- No iCloud `SyncState`, Keychain `SecureState`, or SwiftData `ModelState` +- No plugin system, daemon, or network API +- No dynamic schema language — fixed demo keys only + +## Related + +- [AppState](https://github.com/0xLeif/AppState) — the library this CLI exercises diff --git a/Sources/aps/Aps.swift b/Sources/aps/Aps.swift new file mode 100644 index 0000000..3d6f978 --- /dev/null +++ b/Sources/aps/Aps.swift @@ -0,0 +1,115 @@ +import ArgumentParser +import AppState +import Foundation + +@main +struct Aps: ParsableCommand { + static let configuration = CommandConfiguration( + commandName: "aps", + abstract: "A tiny CLI that dogfoods AppState outside SwiftUI.", + discussion: """ + Demo keys (fixed schema for v1): + counter Int State (in-memory) + message String State (in-memory) + flag Bool StoredState (UserDefaults) + note String FileState (~/.aps/note.json) + + Built on https://github.com/0xLeif/AppState + """, + version: "0.1.0", + subcommands: [Get.self, Set.self, Watch.self, Dump.self], + defaultSubcommand: nil + ) +} + +extension Aps { + struct Get: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "Print the current value for a demo key." + ) + + @Argument(help: "Demo key: counter | message | flag | note") + var key: DemoKey + + func run() throws { + try onMainThread { + Application.logging(isEnabled: false) + let store = StateStore() + print(store.get(key)) + } + } + } + + struct Set: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "Set a demo key to a value." + ) + + @Argument(help: "Demo key: counter | message | flag | note") + var key: DemoKey + + @Argument(help: "New value (Bool: true/false/1/0; Int for counter)") + var value: String + + func run() throws { + try onMainThread { + Application.logging(isEnabled: false) + let store = StateStore() + try store.set(key, value: value) + print(store.get(key)) + } + } + } + + struct Watch: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "Print the value whenever it changes (Observation + polling)." + ) + + @Argument(help: "Demo key: counter | message | flag | note") + var key: DemoKey + + @Option(name: .long, help: "Poll interval in milliseconds (fallback for disk-backed keys).") + var interval: UInt64 = 250 + + func run() throws { + try onMainThread { + Application.logging(isEnabled: false) + let store = StateStore() + store.watchBlocking(key, pollInterval: TimeInterval(interval) / 1000.0) { value in + // Write via FileHandle so output appears immediately when stdout is not a TTY. + if let data = (value + "\n").data(using: .utf8) { + FileHandle.standardOutput.write(data) + } + } + } + } + } + + struct Dump: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "Print all known demo keys as pretty JSON." + ) + + func run() throws { + try onMainThread { + Application.logging(isEnabled: false) + let store = StateStore() + print(try store.dump()) + } + } + } +} + +/// Synchronous `@main` starts on the real main thread; treat that as MainActor for AppState. +private func onMainThread( + _ body: @MainActor () throws -> T +) throws -> T { + precondition( + Thread.isMainThread, + "aps must run on the main thread so AppState can notify observers" + ) + return try MainActor.assumeIsolated { + try body() + } +} diff --git a/Sources/aps/DemoKey.swift b/Sources/aps/DemoKey.swift new file mode 100644 index 0000000..5f09b52 --- /dev/null +++ b/Sources/aps/DemoKey.swift @@ -0,0 +1,46 @@ +import ArgumentParser +import Foundation + +/// Fixed demo keys the CLI understands. +public enum DemoKey: String, CaseIterable, ExpressibleByArgument, Sendable { + case counter + case message + case flag + case note + + public var storage: String { + switch self { + case .counter, .message: return "State" + case .flag: return "StoredState" + case .note: return "FileState" + } + } + + public var valueType: String { + switch self { + case .counter: return "Int" + case .message, .note: return "String" + case .flag: return "Bool" + } + } +} + +public enum APSError: Error, CustomStringConvertible, Equatable { + case unknownKey(String) + case invalidValue(key: DemoKey, value: String) + case encodingFailed + case decodingFailed + + public var description: String { + switch self { + case .unknownKey(let key): + return "Unknown key '\(key)'. Known keys: \(DemoKey.allCases.map(\.rawValue).joined(separator: ", "))" + case .invalidValue(let key, let value): + return "Invalid value '\(value)' for \(key.rawValue) (\(key.valueType))" + case .encodingFailed: + return "Failed to encode value as UTF-8 JSON" + case .decodingFailed: + return "Failed to decode value from UTF-8 JSON" + } + } +} diff --git a/Sources/aps/DemoState.swift b/Sources/aps/DemoState.swift new file mode 100644 index 0000000..dcf48fa --- /dev/null +++ b/Sources/aps/DemoState.swift @@ -0,0 +1,56 @@ +import AppState +import Foundation + +/// Demo keys registered on `Application` — a tiny fixed schema for the CLI. +/// +/// Future idea: dynamic / user-declared keys without rebuilding. +extension Application { + /// In-memory integer counter (process lifetime). + var counter: State { + state(initial: 0, id: "aps.counter") + } + + /// In-memory string message (process lifetime). + var message: State { + state(initial: "", id: "aps.message") + } + + /// Persisted boolean flag via `UserDefaults` (`StoredState`). + var flag: StoredState { + storedState(initial: false, id: "aps.flag") + } + + /// Persisted note on disk via `FileState`. + @MainActor + var note: FileState { + fileState( + initial: "", + filename: "note.json", + isBase64Encoded: false + ) + } + + /// Wall-clock used when stamping watch/dump output. + var clock: Dependency { + dependency(SystemAPSClock()) + } + + /// Shared JSON encoder for pretty CLI dumps. + var jsonCoding: Dependency { + dependency(JSONCoding()) + } +} + +/// Stable paths for CLI-persisted `FileState` data. +enum APSPaths { + @MainActor + static var fileStateDirectory: String { + let home = FileManager.default.homeDirectoryForCurrentUser + return home.appendingPathComponent(".aps", isDirectory: true).path + } + + @MainActor + static func configure() { + FileManager.defaultFileStatePath = fileStateDirectory + } +} diff --git a/Sources/aps/Dependencies.swift b/Sources/aps/Dependencies.swift new file mode 100644 index 0000000..5bb6094 --- /dev/null +++ b/Sources/aps/Dependencies.swift @@ -0,0 +1,36 @@ +import Foundation + +/// Clock abstraction injected through AppState. +public protocol APSClock: Sendable { + var now: Date { get } +} + +/// Production clock backed by `Date()`. +public struct SystemAPSClock: APSClock { + public init() {} + + public var now: Date { Date() } +} + +/// Real JSON helpers used by dump / formatting — not a stub. +public struct JSONCoding: Sendable { + public init() {} + + public func encodePretty(_ value: T) throws -> String { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + encoder.dateEncodingStrategy = .iso8601 + let data = try encoder.encode(value) + guard let string = String(data: data, encoding: .utf8) else { + throw APSError.encodingFailed + } + return string + } + + public func decode(_ type: T.Type, from string: String) throws -> T { + guard let data = string.data(using: .utf8) else { + throw APSError.decodingFailed + } + return try JSONDecoder().decode(type, from: data) + } +} diff --git a/Sources/aps/StateStore.swift b/Sources/aps/StateStore.swift new file mode 100644 index 0000000..0087f20 --- /dev/null +++ b/Sources/aps/StateStore.swift @@ -0,0 +1,161 @@ +import AppState +import Foundation +import Observation + +/// Reads and writes demo keys through AppState idioms (including `@AppDependency`). +/// +/// Callers must be on the main thread — AppState asserts that in `notifyChange()`, +/// and ArgumentParser's synchronous `@main` entry point provides that. +@MainActor +public final class StateStore { + @AppDependency(\.clock) private var clock: any APSClock + @AppDependency(\.jsonCoding) private var jsonCoding: JSONCoding + + public init() { + APSPaths.configure() + Application.load(dependency: \.clock) + Application.load(dependency: \.jsonCoding) + } + + public func get(_ key: DemoKey) -> String { + switch key { + case .counter: + return String(Application.state(\.counter).value) + case .message: + return Application.state(\.message).value + case .flag: + return String(Application.state(\.flag).value) + case .note: + return Application.fileState(\.note).value + } + } + + public func set(_ key: DemoKey, value: String) throws { + switch key { + case .counter: + guard let intValue = Int(value) else { + throw APSError.invalidValue(key: key, value: value) + } + var state = Application.state(\.counter) + state.value = intValue + case .message: + var state = Application.state(\.message) + state.value = value + case .flag: + guard let boolValue = Self.parseBool(value) else { + throw APSError.invalidValue(key: key, value: value) + } + var state = Application.state(\.flag) + state.value = boolValue + // Linux Foundation does not always flush UserDefaults on process exit. + UserDefaults.standard.synchronize() + case .note: + var state = Application.fileState(\.note) + state.value = value + } + } + + public func dump() throws -> String { + let snapshot = DumpSnapshot( + timestamp: clock.now, + keys: DemoKey.allCases.map { key in + DumpEntry( + key: key.rawValue, + storage: key.storage, + type: key.valueType, + value: get(key) + ) + } + ) + return try jsonCoding.encodePretty(snapshot) + } + + /// Blocking watch for the synchronous CLI: Observation + RunLoop polling. + /// + /// - Observation covers in-process mutations (`State`). + /// - Polling re-reads values so `FileState` / `StoredState` updates can surface when + /// Observation alone would not (e.g. another process wrote the file). + public func watchBlocking( + _ key: DemoKey, + pollInterval: TimeInterval = 0.25, + onChange: (String) -> Void + ) { + var last = get(key) + onChange(last) + + let slice = max(pollInterval / 5.0, 0.05) + + while true { + let flag = ChangeFlag() + + withObservationTracking { + self.readForObservation(key) + } onChange: { + flag.mark() + } + + while true { + RunLoop.current.run(until: Date(timeIntervalSinceNow: slice)) + let current = get(key) + if flag.isSet || current != last { + if current != last { + last = current + onChange(current) + } + break + } + } + } + } + + private func readForObservation(_ key: DemoKey) { + switch key { + case .counter: + _ = Application.state(\.counter).value + case .message: + _ = Application.state(\.message).value + case .flag: + _ = Application.state(\.flag).value + case .note: + _ = Application.fileState(\.note).value + } + } + + public nonisolated static func parseBool(_ value: String) -> Bool? { + switch value.lowercased() { + case "true", "1", "yes", "y", "on": return true + case "false", "0", "no", "n", "off": return false + default: return nil + } + } +} + +/// `@Sendable` flag for Observation `onChange` closures. +private final class ChangeFlag: @unchecked Sendable { + private let lock = NSLock() + private var value = false + + func mark() { + lock.lock() + value = true + lock.unlock() + } + + var isSet: Bool { + lock.lock() + defer { lock.unlock() } + return value + } +} + +private struct DumpSnapshot: Encodable { + let timestamp: Date + let keys: [DumpEntry] +} + +private struct DumpEntry: Encodable { + let key: String + let storage: String + let type: String + let value: String +} diff --git a/Tests/apsTests/APSTests.swift b/Tests/apsTests/APSTests.swift new file mode 100644 index 0000000..8d801c6 --- /dev/null +++ b/Tests/apsTests/APSTests.swift @@ -0,0 +1,104 @@ +import AppState +import Foundation +import XCTest +@testable import aps + +final class APSTests: XCTestCase { + override func setUp() async throws { + try await super.setUp() + + await MainActor.run { + Application.logging(isEnabled: false) + + // Isolate FileState under a unique temp directory for this test run. + let path = FileManager.default.temporaryDirectory + .appendingPathComponent("aps-tests-\(UUID().uuidString)", isDirectory: true) + .path + FileManager.defaultFileStatePath = path + try? FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true) + + Application.reset(\.counter) + Application.reset(\.message) + Application.reset(storedState: \.flag) + Application.reset(fileState: \.note) + } + } + + func testParseBool() { + XCTAssertEqual(StateStore.parseBool("true"), true) + XCTAssertEqual(StateStore.parseBool("YES"), true) + XCTAssertEqual(StateStore.parseBool("1"), true) + XCTAssertEqual(StateStore.parseBool("false"), false) + XCTAssertEqual(StateStore.parseBool("off"), false) + XCTAssertNil(StateStore.parseBool("maybe")) + } + + func testDemoKeyMetadata() { + XCTAssertEqual(DemoKey.counter.storage, "State") + XCTAssertEqual(DemoKey.flag.storage, "StoredState") + XCTAssertEqual(DemoKey.note.storage, "FileState") + XCTAssertEqual(DemoKey.counter.valueType, "Int") + } + + @MainActor + func testCounterRoundTrip() async throws { + let store = StateStore() + try store.set(.counter, value: "7") + XCTAssertEqual(store.get(.counter), "7") + try store.set(.counter, value: "42") + XCTAssertEqual(store.get(.counter), "42") + } + + @MainActor + func testMessageAndFlagRoundTrip() async throws { + let store = StateStore() + try store.set(.message, value: "hello") + XCTAssertEqual(store.get(.message), "hello") + + try store.set(.flag, value: "true") + XCTAssertEqual(store.get(.flag), "true") + try store.set(.flag, value: "0") + XCTAssertEqual(store.get(.flag), "false") + } + + @MainActor + func testNoteFileStateRoundTrip() async throws { + let store = StateStore() + try store.set(.note, value: "persisted note") + XCTAssertEqual(store.get(.note), "persisted note") + } + + @MainActor + func testInvalidCounterValue() async { + let store = StateStore() + do { + try store.set(.counter, value: "nope") + XCTFail("Expected invalid value error") + } catch let error as APSError { + XCTAssertEqual(error, .invalidValue(key: .counter, value: "nope")) + } catch { + XCTFail("Unexpected error: \(error)") + } + } + + @MainActor + func testDumpIncludesKeysAndUsesDependency() async throws { + let store = StateStore() + try store.set(.counter, value: "3") + try store.set(.message, value: "hi") + + let json = try store.dump() + XCTAssertTrue(json.contains("\"key\" : \"counter\"")) + XCTAssertTrue(json.contains("\"value\" : \"3\"")) + XCTAssertTrue(json.contains("\"key\" : \"message\"")) + XCTAssertTrue(json.contains("\"storage\" : \"FileState\"")) + XCTAssertTrue(json.contains("timestamp")) + } + + @MainActor + func testJSONCodingDependency() async throws { + let coding = Application.dependency(\.jsonCoding) + let encoded = try coding.encodePretty(["ok": true]) + XCTAssertTrue(encoded.contains("true")) + } +} From 4340cdf1ea69e060946f4e418e2b0ea02c7e9144 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 18 Jul 2026 16:22:17 +0000 Subject: [PATCH 2/9] Expand CLI with keys/reset, watch tests, and CI Add keys/reset commands, Observation watch coverage, Linux/macOS workflows, and a smoke script that respects process-local State. Co-authored-by: Leif --- .github/workflows/linux.yml | 25 +++++++++++ .github/workflows/macos.yml | 23 +++++++++++ README.md | 23 +++++++++-- Scripts/smoke.sh | 45 ++++++++++++++++++++ Sources/aps/Aps.swift | 78 +++++++++++++++++++++++++++++++---- Sources/aps/DemoKey.swift | 18 ++++++++ Sources/aps/StateStore.swift | 26 +++++++++++- Tests/apsTests/APSTests.swift | 78 +++++++++++++++++++++++++++++++++++ 8 files changed, 302 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/linux.yml create mode 100644 .github/workflows/macos.yml create mode 100755 Scripts/smoke.sh diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 0000000..d81d701 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,25 @@ +name: Linux + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Swift + uses: swift-actions/setup-swift@v2 + with: + swift-version: "6.1.0" + - name: Build + run: swift build -c release + - name: Test + run: swift test + - name: Smoke CLI + env: + APS_BIN: .build/release/aps + run: ./Scripts/smoke.sh diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml new file mode 100644 index 0000000..213a539 --- /dev/null +++ b/.github/workflows/macos.yml @@ -0,0 +1,23 @@ +name: macOS + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +jobs: + build-and-test: + runs-on: macos-15 + steps: + - uses: actions/checkout@v4 + - name: Swift version + run: swift --version + - name: Build + run: swift build -c release + - name: Test + run: swift test + - name: Smoke CLI + env: + APS_BIN: .build/release/aps + run: ./Scripts/smoke.sh diff --git a/README.md b/README.md index 4fc4f45..5deedac 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ aps get aps set aps watch # print on change (Observation + polling) aps dump # print all known state as JSON +aps keys # list demo keys / storage kinds +aps reset # restore one key to its initial value +aps reset --all aps --help ``` @@ -30,7 +33,7 @@ Dynamic / user-declared keys are intentionally out of scope for v1. `aps` injects real services with `@AppDependency` / `Application.dependency`: - **`clock`** — wall clock for dump timestamps -- **`jsonCoding`** — shared `JSONEncoder` helpers for `aps dump` +- **`jsonCoding`** — shared JSON encoder helpers for `aps dump` ## Requirements @@ -56,6 +59,9 @@ swift build -c release ### Examples ```bash +# Discover the fixed schema +swift run aps keys + # In-memory State swift run aps set counter 3 swift run aps get counter @@ -71,9 +77,13 @@ swift run aps dump # Watch for changes (Ctrl+C to stop) swift run aps watch note --interval 200 + +# Reset +swift run aps reset counter +swift run aps reset --all ``` -`watch` uses Swift Observation for in-process updates and polls as a fallback so disk-backed `FileState` / `StoredState` changes can still surface. +`watch` uses Swift Observation for in-process updates and polls as a fallback so disk-backed `FileState` / `StoredState` changes can still surface — including updates written by another `aps` process. ## Tests @@ -81,12 +91,19 @@ swift run aps watch note --interval 200 swift test ``` +CI builds and smokes the CLI on Linux and macOS (see `.github/workflows`). Locally: + +```bash +./Scripts/smoke.sh +``` + ## Layout ```text Package.swift Sources/aps/ # executable + AppState demo surface -Tests/apsTests/ # parsing + state round-trips +Tests/apsTests/ # parsing, round-trips, watch, reset +.github/workflows/ # Linux + macOS CI ``` ## Non-goals (v1) diff --git a/Scripts/smoke.sh b/Scripts/smoke.sh new file mode 100755 index 0000000..d0c3f75 --- /dev/null +++ b/Scripts/smoke.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +root="$(cd "$(dirname "$0")/.." && pwd)" +cd "$root" + +if [[ -z "${APS_BIN:-}" ]]; then + swift build -c debug + APS_BIN=".build/debug/aps" +fi +bin="$APS_BIN" + +"$bin" --help >/dev/null +"$bin" keys | grep -q counter + +# `set` prints the value; State is process-local so don't expect get in a new process. +test "$("$bin" set counter 11)" = "11" +test "$("$bin" set message "smoke")" = "smoke" + +# StoredState / FileState must survive process boundaries. +"$bin" set flag true >/dev/null +test "$("$bin" get flag)" = "true" + +"$bin" set note "smoke-note" >/dev/null +test "$("$bin" get note)" = "smoke-note" + +"$bin" dump | grep -q '"key" : "flag"' + +"$bin" reset flag >/dev/null +test "$("$bin" get flag)" = "false" + +"$bin" reset note >/dev/null +test -z "$("$bin" get note)" + +"$bin" reset --all >/dev/null +test "$("$bin" get flag)" = "false" +test -z "$("$bin" get note)" + +# Invalid values should fail clearly. +if "$bin" set counter nope >/dev/null 2>&1; then + echo "expected invalid counter to fail" >&2 + exit 1 +fi + +echo "smoke ok" diff --git a/Sources/aps/Aps.swift b/Sources/aps/Aps.swift index 3d6f978..f863f41 100644 --- a/Sources/aps/Aps.swift +++ b/Sources/aps/Aps.swift @@ -17,7 +17,14 @@ struct Aps: ParsableCommand { Built on https://github.com/0xLeif/AppState """, version: "0.1.0", - subcommands: [Get.self, Set.self, Watch.self, Dump.self], + subcommands: [ + Get.self, + Set.self, + Watch.self, + Dump.self, + Keys.self, + Reset.self + ], defaultSubcommand: nil ) } @@ -33,9 +40,8 @@ extension Aps { func run() throws { try onMainThread { - Application.logging(isEnabled: false) - let store = StateStore() - print(store.get(key)) + boot() + print(StateStore().get(key)) } } } @@ -53,9 +59,13 @@ extension Aps { func run() throws { try onMainThread { - Application.logging(isEnabled: false) + boot() let store = StateStore() - try store.set(key, value: value) + do { + try store.set(key, value: value) + } catch let error as APSError { + throw ValidationError(error.description) + } print(store.get(key)) } } @@ -74,7 +84,7 @@ extension Aps { func run() throws { try onMainThread { - Application.logging(isEnabled: false) + boot() let store = StateStore() store.watchBlocking(key, pollInterval: TimeInterval(interval) / 1000.0) { value in // Write via FileHandle so output appears immediately when stdout is not a TTY. @@ -93,14 +103,64 @@ extension Aps { func run() throws { try onMainThread { - Application.logging(isEnabled: false) + boot() + print(try StateStore().dump()) + } + } + } + + struct Keys: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "List the fixed demo keys and how they are stored." + ) + + func run() throws { + print("KEY\tTYPE\tSTORAGE\tDESCRIPTION") + for key in DemoKey.allCases { + print("\(key.helpSummary)\t\(key.detail)") + } + } + } + + struct Reset: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "Reset one demo key (or all keys) back to its initial value." + ) + + @Argument(help: "Demo key to reset. Omit with --all.") + var key: DemoKey? + + @Flag(name: .long, help: "Reset every demo key.") + var all: Bool = false + + func run() throws { + guard all || key != nil else { + throw ValidationError("Pass a key or --all. Example: aps reset counter") + } + if all && key != nil { + throw ValidationError("Pass either a key or --all, not both.") + } + + try onMainThread { + boot() let store = StateStore() - print(try store.dump()) + if all { + store.resetAll() + print("reset all keys") + } else if let key { + store.reset(key) + print(store.get(key)) + } } } } } +@MainActor +private func boot() { + Application.logging(isEnabled: false) +} + /// Synchronous `@main` starts on the real main thread; treat that as MainActor for AppState. private func onMainThread( _ body: @MainActor () throws -> T diff --git a/Sources/aps/DemoKey.swift b/Sources/aps/DemoKey.swift index 5f09b52..18ec641 100644 --- a/Sources/aps/DemoKey.swift +++ b/Sources/aps/DemoKey.swift @@ -23,6 +23,24 @@ public enum DemoKey: String, CaseIterable, ExpressibleByArgument, Sendable { case .flag: return "Bool" } } + + public var helpSummary: String { + "\(rawValue)\t\(valueType)\t\(storage)" + } + + /// Human-readable one-liner for `aps keys`. + public var detail: String { + switch self { + case .counter: + return "in-memory Int counter (process lifetime)" + case .message: + return "in-memory String (process lifetime)" + case .flag: + return "Bool via StoredState / UserDefaults" + case .note: + return "String via FileState (~/.aps/note.json)" + } + } } public enum APSError: Error, CustomStringConvertible, Equatable { diff --git a/Sources/aps/StateStore.swift b/Sources/aps/StateStore.swift index 0087f20..51a7015 100644 --- a/Sources/aps/StateStore.swift +++ b/Sources/aps/StateStore.swift @@ -55,6 +55,26 @@ public final class StateStore { } } + public func reset(_ key: DemoKey) { + switch key { + case .counter: + Application.reset(\.counter) + case .message: + Application.reset(\.message) + case .flag: + Application.reset(storedState: \.flag) + UserDefaults.standard.synchronize() + case .note: + Application.reset(fileState: \.note) + } + } + + public func resetAll() { + for key in DemoKey.allCases { + reset(key) + } + } + public func dump() throws -> String { let snapshot = DumpSnapshot( timestamp: clock.now, @@ -75,9 +95,11 @@ public final class StateStore { /// - Observation covers in-process mutations (`State`). /// - Polling re-reads values so `FileState` / `StoredState` updates can surface when /// Observation alone would not (e.g. another process wrote the file). + /// - `shouldContinue` lets tests (and future tooling) stop the loop cleanly. public func watchBlocking( _ key: DemoKey, pollInterval: TimeInterval = 0.25, + shouldContinue: () -> Bool = { true }, onChange: (String) -> Void ) { var last = get(key) @@ -85,7 +107,7 @@ public final class StateStore { let slice = max(pollInterval / 5.0, 0.05) - while true { + while shouldContinue() { let flag = ChangeFlag() withObservationTracking { @@ -94,7 +116,7 @@ public final class StateStore { flag.mark() } - while true { + while shouldContinue() { RunLoop.current.run(until: Date(timeIntervalSinceNow: slice)) let current = get(key) if flag.isSet || current != last { diff --git a/Tests/apsTests/APSTests.swift b/Tests/apsTests/APSTests.swift index 8d801c6..e97a507 100644 --- a/Tests/apsTests/APSTests.swift +++ b/Tests/apsTests/APSTests.swift @@ -38,6 +38,8 @@ final class APSTests: XCTestCase { XCTAssertEqual(DemoKey.flag.storage, "StoredState") XCTAssertEqual(DemoKey.note.storage, "FileState") XCTAssertEqual(DemoKey.counter.valueType, "Int") + XCTAssertEqual(DemoKey.allCases.count, 4) + XCTAssertTrue(DemoKey.note.detail.contains("FileState")) } @MainActor @@ -101,4 +103,80 @@ final class APSTests: XCTestCase { let encoded = try coding.encodePretty(["ok": true]) XCTAssertTrue(encoded.contains("true")) } + + @MainActor + func testResetRestoresInitialValues() async throws { + let store = StateStore() + try store.set(.counter, value: "9") + try store.set(.message, value: "x") + try store.set(.flag, value: "true") + try store.set(.note, value: "n") + + store.reset(.counter) + store.reset(.message) + store.reset(.flag) + store.reset(.note) + + XCTAssertEqual(store.get(.counter), "0") + XCTAssertEqual(store.get(.message), "") + XCTAssertEqual(store.get(.flag), "false") + XCTAssertEqual(store.get(.note), "") + } + + @MainActor + func testResetAll() async throws { + let store = StateStore() + try store.set(.counter, value: "5") + try store.set(.note, value: "keep?") + store.resetAll() + XCTAssertEqual(store.get(.counter), "0") + XCTAssertEqual(store.get(.note), "") + } + + @MainActor + func testWatchDetectsInProcessStateChange() async throws { + let store = StateStore() + try store.set(.counter, value: "1") + + var seen: [String] = [] + store.watchBlocking( + .counter, + pollInterval: 0.05, + shouldContinue: { seen.count < 2 } + ) { value in + seen.append(value) + if value == "1" { + try? store.set(.counter, value: "2") + } + } + + XCTAssertEqual(seen, ["1", "2"]) + } + + @MainActor + func testWatchDetectsFileStateChange() async throws { + let store = StateStore() + try store.set(.note, value: "before") + + var seen: [String] = [] + store.watchBlocking( + .note, + pollInterval: 0.05, + shouldContinue: { seen.count < 2 } + ) { value in + seen.append(value) + if value == "before" { + try? store.set(.note, value: "after") + } + } + + XCTAssertEqual(seen, ["before", "after"]) + } + + @MainActor + func testClockDependencyIsInjectable() async throws { + let clock = Application.dependency(\.clock) + let before = clock.now + XCTAssertLessThanOrEqual(before.timeIntervalSinceNow, 0) + } } From f4bd6f9adbc83a4ebaa8760a08f1f699566638f9 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 18 Jul 2026 16:27:37 +0000 Subject: [PATCH 3/9] Adopt CorvidLabs trust stack on macOS self-hosted CI Wire fledge, SpecSync, augur, and attest; author aps-cli/state-store specs; replace hosted Linux/macOS jobs with self-hosted macOS runners while the repository is private. Co-authored-by: Leif --- .attest.json | 6 + .augur.toml | 3 + .github/workflows/ci.yml | 35 ++++++ .github/workflows/linux.yml | 25 ----- .github/workflows/macos.yml | 23 ---- .github/workflows/trust.yml | 34 ++++++ .gitignore | 3 + .specsync/.gitignore | 5 + .specsync/change-sequence.json | 6 + .../approvals.json | 19 ++++ .../change.md | 24 ++++ .../context.md | 8 ++ .../design.md | 8 ++ .../docs.md | 8 ++ .../plan.md | 8 ++ .../research.md | 8 ++ .../state.json | 50 +++++++++ .../tasks.md | 14 +++ .../testing.md | 8 ++ .../verification-attempts.json | 20 ++++ .../verification.json | 15 +++ .specsync/config.toml | 11 ++ .specsync/registry.toml | 6 + .specsync/sdd.json | 31 +++++ .specsync/version | 1 + .trust.toml | 22 ++++ AGENTS.md | 47 ++++++++ CLAUDE.md | 1 + README.md | 77 ++++++++----- Sources/aps/DemoState.swift | 2 +- Sources/aps/Dependencies.swift | 2 +- Sources/aps/StateStore.swift | 2 +- fledge.toml | 14 +++ specs/aps-cli/aps-cli.spec.md | 106 ++++++++++++++++++ specs/state-store/state-store.spec.md | 103 +++++++++++++++++ 35 files changed, 676 insertions(+), 79 deletions(-) create mode 100644 .attest.json create mode 100644 .augur.toml create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/linux.yml delete mode 100644 .github/workflows/macos.yml create mode 100644 .github/workflows/trust.yml create mode 100644 .specsync/.gitignore create mode 100644 .specsync/change-sequence.json create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/approvals.json create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/change.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/context.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/design.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/docs.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/plan.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/research.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/state.json create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/tasks.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/testing.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification-attempts.json create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification.json create mode 100644 .specsync/config.toml create mode 100644 .specsync/registry.toml create mode 100644 .specsync/sdd.json create mode 100644 .specsync/version create mode 100644 .trust.toml create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 fledge.toml create mode 100644 specs/aps-cli/aps-cli.spec.md create mode 100644 specs/state-store/state-store.spec.md diff --git a/.attest.json b/.attest.json new file mode 100644 index 0000000..2ebd680 --- /dev/null +++ b/.attest.json @@ -0,0 +1,6 @@ +{ + "requireAttestation": false, + "requireTestsPassed": false, + "requireSignature": false, + "requireHumanApprovalWhenVerdictAtLeast": "block" +} diff --git a/.augur.toml b/.augur.toml new file mode 100644 index 0000000..031b459 --- /dev/null +++ b/.augur.toml @@ -0,0 +1,3 @@ +[thresholds] +review = 35 +block = 65 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5c7100f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: CI + +# Private repo: run on macOS self-hosted runners (not GitHub-hosted). +# Revisit before making the repository public: fork PRs must not run on +# self-hosted hosts. + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +permissions: + contents: read + +jobs: + build-test-smoke: + runs-on: [self-hosted, macOS] + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - name: Swift version + run: swift --version + - name: Build (release) + run: swift build -c release + - name: Test + run: swift test + - name: Smoke CLI + env: + APS_BIN: .build/release/aps + run: ./Scripts/smoke.sh diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml deleted file mode 100644 index d81d701..0000000 --- a/.github/workflows/linux.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Linux - -on: - push: - branches: ["main"] - pull_request: - branches: ["main"] - -jobs: - build-and-test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up Swift - uses: swift-actions/setup-swift@v2 - with: - swift-version: "6.1.0" - - name: Build - run: swift build -c release - - name: Test - run: swift test - - name: Smoke CLI - env: - APS_BIN: .build/release/aps - run: ./Scripts/smoke.sh diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml deleted file mode 100644 index 213a539..0000000 --- a/.github/workflows/macos.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: macOS - -on: - push: - branches: ["main"] - pull_request: - branches: ["main"] - -jobs: - build-and-test: - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Swift version - run: swift --version - - name: Build - run: swift build -c release - - name: Test - run: swift test - - name: Smoke CLI - env: - APS_BIN: .build/release/aps - run: ./Scripts/smoke.sh diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml new file mode 100644 index 0000000..b3cddbf --- /dev/null +++ b/.github/workflows/trust.yml @@ -0,0 +1,34 @@ +name: Trust + +# Private repo: CorvidLabs trust gate on macOS self-hosted runners. +# Revisit before making the repository public: fork PRs must not run on +# self-hosted hosts. + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + trust: + runs-on: [self-hosted, macOS] + timeout-minutes: 45 + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v4.1.6 + with: + fetch-depth: 0 + + - name: Fetch attest notes + run: git fetch origin "+refs/notes/attest:refs/notes/attest" 2>/dev/null || true + + - name: CorvidLabs Trust gate + id: trust + uses: CorvidLabs/trust@9d32b5786d2e9e4d39fc581c0091c721ee3d4226 # v1.0.0 + + - name: Check managed agent rules + run: | + grep -q "CorvidLabs trust toolchain: BEGIN" AGENTS.md + grep -q "CorvidLabs trust toolchain: END" AGENTS.md diff --git a/.gitignore b/.gitignore index f24f582..1ecb30a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ DerivedData/ .netrc *.swp *~ + +# CorvidLabs trust toolchain +augur.json diff --git a/.specsync/.gitignore b/.specsync/.gitignore new file mode 100644 index 0000000..6c6df34 --- /dev/null +++ b/.specsync/.gitignore @@ -0,0 +1,5 @@ +cache/ +change.lock +hashes.json +*.local +# Local SpecSync caches / working files diff --git a/.specsync/change-sequence.json b/.specsync/change-sequence.json new file mode 100644 index 0000000..bccaaa2 --- /dev/null +++ b/.specsync/change-sequence.json @@ -0,0 +1,6 @@ +{ + "schema_version": 1, + "sequence": 1, + "id": "CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli", + "acknowledged_collisions": [] +} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/approvals.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/approvals.json new file mode 100644 index 0000000..97ac732 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/approvals.json @@ -0,0 +1,19 @@ +{ + "approvals": [ + { + "gate": "definition", + "actor": "agent:cursor", + "timestamp": 1784392032, + "digest": "fa4a28bbc4403e69844dd6de124cc599c5cf7fa0047bdb9107b02e9135eb99e7", + "note": "Approved CorvidLabs trust adoption for private aps-cli with self-hosted macOS CI." + }, + { + "gate": "definition", + "actor": "agent:cursor", + "timestamp": 1784392047, + "digest": "0b7711988c6850f3a9f0bf39151dd32f8fdb09821e0c214c26aefe3b8599565c", + "note": "Re-approved after completing migration tasks." + } + ], + "reopenings": [] +} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/change.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/change.md new file mode 100644 index 0000000..f69f326 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/change.md @@ -0,0 +1,24 @@ +--- +id: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli +state: implementing +type: migration +base_commit: 4340cdf1ea69e060946f4e418e2b0ea02c7e9144 +--- + +# Adopt CorvidLabs trust toolchain for the private aps CLI + +## Intent + +Adopt CorvidLabs trust toolchain for the private aps CLI + +## Affected Canonical Specs + +- None + +## Acceptance Criteria + +- fledge verify lane builds tests and smokes aps; SpecSync registry lists aps-cli and state-store; Trust config and AGENTS.md markers are committed; CI and Trust workflows run on self-hosted macOS only + +## No-spec Rationale + +Bootstrap governance, CI, and committed module contracts without applying semantic deltas; aps-cli and state-store specs are authored as canonical companions in the same PR. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/context.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/context.md new file mode 100644 index 0000000..4d05439 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/context.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli +artifact: context +--- + +# Context + +aps-cli is a private Swift package that dogfoods AppState as a CLI. This migration wires the CorvidLabs trust toolchain and moves CI onto macOS self-hosted runners while the repository remains private. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/design.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/design.md new file mode 100644 index 0000000..e8c0ebc --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/design.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli +artifact: design +--- + +# Design + +Keep a standard Trust profile with soft provenance. Commit module specs for aps-cli and state-store as canonical companions. CI and Trust workflows both use runs-on: [self-hosted, macOS]. fledge lanes.verify runs build, test, and smoke. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/docs.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/docs.md new file mode 100644 index 0000000..e45db85 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/docs.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli +artifact: docs +--- + +# Docs + +README documents commands, trust files, and the private-repo self-hosted runner policy. AGENTS.md carries the managed CorvidLabs trust toolchain block. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/plan.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/plan.md new file mode 100644 index 0000000..1f905da --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/plan.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli +artifact: plan +--- + +# Plan + +1. Commit trust config and SpecSync policy. 2. Author module specs. 3. Replace hosted Linux/macOS workflows with self-hosted CI and Trust. 4. Approve and start this migration change. 5. Confirm runners pick up checks on the PR. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/research.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/research.md new file mode 100644 index 0000000..7b4d1c0 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/research.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli +artifact: research +--- + +# Research + +CorvidLabs Trust 1 composes fledge, SpecSync 5, augur, and attest. The corvid-stack template and https://corvidlabs.xyz/integrate/ define the adoption shape. Self-hosted macOS runners are appropriate for private repos; hosted runners should be restored before public fork PR exposure. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/state.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/state.json new file mode 100644 index 0000000..17d0034 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/state.json @@ -0,0 +1,50 @@ +{ + "schema_version": 1, + "id": "CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli", + "slug": "adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli", + "title": "Adopt CorvidLabs trust toolchain for the private aps CLI", + "description": "Adopt CorvidLabs trust toolchain for the private aps CLI", + "kind": "migration", + "state": "verifying", + "base_commit": "4340cdf1ea69e060946f4e418e2b0ea02c7e9144", + "created_at": 1784392021, + "updated_at": 1784392050, + "affected_specs": [], + "affected_paths": [ + ".github/workflows/", + ".specsync/", + "specs/", + "Sources/", + "Tests/", + "Scripts/", + "fledge.toml", + ".trust.toml", + ".augur.toml", + ".attest.json", + "AGENTS.md", + "CLAUDE.md", + "README.md", + "Package.swift", + "Package.resolved", + ".gitignore" + ], + "no_spec_change": true, + "no_spec_change_rationale": "Bootstrap governance, CI, and committed module contracts without applying semantic deltas; aps-cli and state-store specs are authored as canonical companions in the same PR.", + "acceptance_criteria": [ + "fledge verify lane builds tests and smokes aps; SpecSync registry lists aps-cli and state-store; Trust config and AGENTS.md markers are committed; CI and Trust workflows run on self-hosted macOS only" + ], + "selected_artifacts": [ + "context", + "research", + "design", + "plan", + "tasks", + "testing", + "docs" + ], + "dependencies": [], + "answers": { + "architecture_risk": "no", + "public_contract": "no" + } +} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/tasks.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/tasks.md new file mode 100644 index 0000000..f38e17c --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/tasks.md @@ -0,0 +1,14 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli +artifact: tasks +--- + +# Tasks + +- [x] Add fledge.toml verify lane (build/test/smoke) +- [x] Add .trust.toml, .augur.toml, .attest.json +- [x] Add SpecSync config, registry, SDD policy, version pin +- [x] Author aps-cli and state-store specs +- [x] Add AGENTS.md managed trust block and CLAUDE.md pointer +- [x] Move CI/Trust workflows to [self-hosted, macOS] +- [x] Pass local `fledge trust verify` (progressive provenance) diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/testing.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/testing.md new file mode 100644 index 0000000..3c4ad30 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/testing.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli +artifact: testing +--- + +# Testing + +Local: fledge lanes run verify, swift test, Scripts/smoke.sh, fledge trust doctor. CI: CI workflow smokes the release binary; Trust workflow runs CorvidLabs/trust@v1 and greps AGENTS.md markers. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification-attempts.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification-attempts.json new file mode 100644 index 0000000..2ef0da2 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification-attempts.json @@ -0,0 +1,20 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1784392050, + "commit": "4340cdf1ea69e060946f4e418e2b0ea02c7e9144", + "contract_digest": "0b7711988c6850f3a9f0bf39151dd32f8fdb09821e0c214c26aefe3b8599565c", + "workspace_digest": "6b67f53d36cc2d782bc41d6f53e5314904ed19666d1c475d87f988f74181134c", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [] + } + ] +} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification.json new file mode 100644 index 0000000..277d7e6 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification.json @@ -0,0 +1,15 @@ +{ + "timestamp": 1784392050, + "commit": "4340cdf1ea69e060946f4e418e2b0ea02c7e9144", + "contract_digest": "0b7711988c6850f3a9f0bf39151dd32f8fdb09821e0c214c26aefe3b8599565c", + "workspace_digest": "6b67f53d36cc2d782bc41d6f53e5314904ed19666d1c475d87f988f74181134c", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [] +} diff --git a/.specsync/config.toml b/.specsync/config.toml new file mode 100644 index 0000000..b4b24fa --- /dev/null +++ b/.specsync/config.toml @@ -0,0 +1,11 @@ +# spec-sync v5 configuration +# Docs: https://github.com/CorvidLabs/spec-sync +specs_dir = "specs" +source_dirs = ["Sources/aps", "Tests/apsTests"] +exclude_dirs = [] +exclude_patterns = [] +required_sections = ["Purpose", "Public API", "Invariants", "Behavioral Examples", "Error Cases", "Dependencies", "Change Log"] +enforcement = "strict" + +[lifecycle] +track_history = false diff --git a/.specsync/registry.toml b/.specsync/registry.toml new file mode 100644 index 0000000..190f57d --- /dev/null +++ b/.specsync/registry.toml @@ -0,0 +1,6 @@ +[registry] +name = "aps" + +[specs] +aps-cli = "specs/aps-cli/aps-cli.spec.md" +state-store = "specs/state-store/state-store.spec.md" diff --git a/.specsync/sdd.json b/.specsync/sdd.json new file mode 100644 index 0000000..7a44ca9 --- /dev/null +++ b/.specsync/sdd.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "enabled": true, + "require_change_for_meaningful_files": true, + "meaningful_paths": [ + ".", + "Sources/", + "Tests/", + "specs/", + ".github/", + "Package.swift", + "Package.resolved", + ".specsync/sdd.json", + ".specsync/config.toml", + ".specsync/registry.toml", + ".specsync/version", + "fledge.toml", + ".trust.toml", + ".augur.toml", + ".attest.json", + "AGENTS.md", + "CLAUDE.md", + "Scripts/" + ], + "ignored_paths": [], + "verification_commands": [ + "fledge lanes run verify" + ], + "custom_artifacts": {}, + "principles_file": null +} diff --git a/.specsync/version b/.specsync/version new file mode 100644 index 0000000..6b244dc --- /dev/null +++ b/.specsync/version @@ -0,0 +1 @@ +5.0.1 diff --git a/.trust.toml b/.trust.toml new file mode 100644 index 0000000..4c56b60 --- /dev/null +++ b/.trust.toml @@ -0,0 +1,22 @@ +schema_version = 1 +profile = "standard" + +[lifecycle] +command = ["fledge", "lanes", "run", "verify"] + +[contract] +enabled = true +require_coverage = 0 +skip_reason = "" + +[risk] +threshold = "block" + +[provenance] +mode = "soft" +policy = ".attest.json" +skip_reason = "" + +[atlas] +enabled = false +skip_reason = "Atlas publication is deferred until GitHub Pages is enabled for this private repo" diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..9bfd9df --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,47 @@ +# aps + +A Swift CLI that dogfoods [AppState](https://github.com/0xLeif/AppState) outside SwiftUI. + +## Layout + +| Path | Role | +|------|------| +| `Sources/aps/` | Executable: CLI, demo Application state, StateStore | +| `Tests/apsTests/` | Round-trip, watch, reset, and dependency tests | +| `specs/` | SpecSync contracts for the CLI and state surface | +| `Scripts/smoke.sh` | End-to-end CLI smoke checks | + +## Workflow + +```sh +fledge lanes run verify # build + test + smoke +fledge trust verify # full trust gate when tools are installed +./Scripts/smoke.sh +``` + + +## CorvidLabs trust toolchain (standing rules) + +This repo is gated by four tools, run by `.github/workflows/trust.yml`: + +1. **fledge**: the quality gate. `fledge lanes run verify` runs + build + test + smoke. Prefer fledge wrappers over raw tools. +2. **spec-sync**: specs are contracts. Each module API has a `*.spec.md`, and + `specsync check` must pass. Skipping spec-sync for a repo needs an explicit + one-line reason. +3. **augur**: deterministic diff-risk scoring. A `block` verdict halts the + merge. `augur.json` is a per-run artifact and is gitignored; never commit it. +4. **attest**: signed provenance. CI records an attestation and verifies the + range against `.attest.json`. Provenance lives in `refs/notes/attest`. + +Standing rules for anyone (human or agent) changing this repo: + +- Run `fledge lanes run verify` before pushing; do not bypass the gate. +- Keep specs in lockstep with code: update the `*.spec.md` in the same change. +- A `block` verdict from augur means stop and escalate, not merge. +- Do not commit `augur.json`. +- Do not use em-dash characters in authored content; use hyphens or colons. +- Runner-specific rule files (`CLAUDE.md`, `.cursor/rules/*.mdc`, + `.github/copilot-instructions.md`) are one-line pointers to this file; do not + duplicate these rules into them. + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..4166c46 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +See AGENTS.md for the project rules, including the managed CorvidLabs trust toolchain block. diff --git a/README.md b/README.md index 5deedac..fb1c645 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ A tiny Swift CLI that [dogfoods](https://github.com/0xLeif/AppState) **AppState** outside SwiftUI: declare typed app state, get/set/watch/dump it, and show dependency injection. -Cross-platform where AppState allows — **macOS** and **Linux** first. +Cross-platform where AppState allows: **macOS** and **Linux** first. + +This repository is gated by the [CorvidLabs trust toolchain](https://corvidlabs.xyz/integrate/) (fledge, spec-sync, augur, attest). See `AGENTS.md`. ## Commands @@ -32,15 +34,16 @@ Dynamic / user-declared keys are intentionally out of scope for v1. `aps` injects real services with `@AppDependency` / `Application.dependency`: -- **`clock`** — wall clock for dump timestamps -- **`jsonCoding`** — shared JSON encoder helpers for `aps dump` +- **`clock`** : wall clock for dump timestamps +- **`jsonCoding`** : shared JSON encoder helpers for `aps dump` ## Requirements - Swift 6.0+ - macOS 14+ or Linux (Swift.org toolchain) +- For the trust gate locally: [corvid-trust](https://github.com/CorvidLabs/trust) (`brew install CorvidLabs/tap/corvid-trust`) -## Build & run +## Build and run ```bash git clone https://github.com/0xLeif/aps-cli.git @@ -49,6 +52,12 @@ swift build swift run aps --help ``` +Or through fledge: + +```bash +fledge lanes run verify +``` + Release build: ```bash @@ -59,59 +68,71 @@ swift build -c release ### Examples ```bash -# Discover the fixed schema swift run aps keys - -# In-memory State swift run aps set counter 3 -swift run aps get counter -swift run aps set message "hello from aps" - -# Persisted StoredState / FileState swift run aps set flag true swift run aps set note "saved across launches" -swift run aps get note - -# Inspect everything (uses injected JSONCoding + clock) swift run aps dump - -# Watch for changes (Ctrl+C to stop) swift run aps watch note --interval 200 - -# Reset -swift run aps reset counter swift run aps reset --all ``` -`watch` uses Swift Observation for in-process updates and polls as a fallback so disk-backed `FileState` / `StoredState` changes can still surface — including updates written by another `aps` process. +`watch` uses Swift Observation for in-process updates and polls as a fallback so disk-backed `FileState` / `StoredState` changes can still surface, including updates written by another `aps` process. -## Tests +## Tests and smoke ```bash swift test +./Scripts/smoke.sh ``` -CI builds and smokes the CLI on Linux and macOS (see `.github/workflows`). Locally: +## CI (private repo) + +While this repository is **private**, every workflow runs on **macOS self-hosted** runners: + +| Workflow | Runner | Role | +|----------|--------|------| +| `.github/workflows/ci.yml` | `[self-hosted, macOS]` | build / test / smoke | +| `.github/workflows/trust.yml` | `[self-hosted, macOS]` | CorvidLabs Trust gate (fledge + spec-sync + augur + attest) | + +Before making the repo public, switch off self-hosted runners for fork pull requests. + +## Trust toolchain + +| File | Purpose | +|------|---------| +| `fledge.toml` | Tasks + `verify` lane | +| `.trust.toml` | Unified Trust policy | +| `.augur.toml` | Diff-risk thresholds | +| `.attest.json` | Provenance policy | +| `.specsync/` | SpecSync 5 config + SDD change tracking | +| `specs/` | Module contracts (`aps-cli`, `state-store`) | +| `AGENTS.md` | Standing rules (managed block required by CI) | ```bash -./Scripts/smoke.sh +fledge trust doctor +fledge trust verify ``` ## Layout ```text Package.swift -Sources/aps/ # executable + AppState demo surface -Tests/apsTests/ # parsing, round-trips, watch, reset -.github/workflows/ # Linux + macOS CI +Sources/aps/ +Tests/apsTests/ +specs/ +Scripts/smoke.sh +.github/workflows/{ci,trust}.yml ``` ## Non-goals (v1) - No iCloud `SyncState`, Keychain `SecureState`, or SwiftData `ModelState` - No plugin system, daemon, or network API -- No dynamic schema language — fixed demo keys only +- No dynamic schema language: fixed demo keys only ## Related -- [AppState](https://github.com/0xLeif/AppState) — the library this CLI exercises +- [AppState](https://github.com/0xLeif/AppState) +- [CorvidLabs Trust](https://github.com/CorvidLabs/trust) +- [Integrate guide](https://corvidlabs.xyz/integrate/) diff --git a/Sources/aps/DemoState.swift b/Sources/aps/DemoState.swift index dcf48fa..2ad0d7b 100644 --- a/Sources/aps/DemoState.swift +++ b/Sources/aps/DemoState.swift @@ -1,7 +1,7 @@ import AppState import Foundation -/// Demo keys registered on `Application` — a tiny fixed schema for the CLI. +/// Demo keys registered on `Application`: a tiny fixed schema for the CLI. /// /// Future idea: dynamic / user-declared keys without rebuilding. extension Application { diff --git a/Sources/aps/Dependencies.swift b/Sources/aps/Dependencies.swift index 5bb6094..e85349b 100644 --- a/Sources/aps/Dependencies.swift +++ b/Sources/aps/Dependencies.swift @@ -12,7 +12,7 @@ public struct SystemAPSClock: APSClock { public var now: Date { Date() } } -/// Real JSON helpers used by dump / formatting — not a stub. +/// Real JSON helpers used by dump / formatting: not a stub. public struct JSONCoding: Sendable { public init() {} diff --git a/Sources/aps/StateStore.swift b/Sources/aps/StateStore.swift index 51a7015..3a1f135 100644 --- a/Sources/aps/StateStore.swift +++ b/Sources/aps/StateStore.swift @@ -4,7 +4,7 @@ import Observation /// Reads and writes demo keys through AppState idioms (including `@AppDependency`). /// -/// Callers must be on the main thread — AppState asserts that in `notifyChange()`, +/// Callers must be on the main thread: AppState asserts that in `notifyChange()`, /// and ArgumentParser's synchronous `@main` entry point provides that. @MainActor public final class StateStore { diff --git a/fledge.toml b/fledge.toml new file mode 100644 index 0000000..d2d56a7 --- /dev/null +++ b/fledge.toml @@ -0,0 +1,14 @@ +# fledge.toml: aps CLI lifecycle tasks +# Docs: https://github.com/CorvidLabs/fledge + +[tasks] +build = "swift build" +test = "swift test" +release-build = "swift build -c release" +smoke = "./Scripts/smoke.sh" +spec = "specsync check" +check = "fledge run build && fledge run test && fledge run smoke" + +[lanes.verify] +description = "Build, test, and smoke aps (the single quality gate)" +steps = ["build", "test", "smoke"] diff --git a/specs/aps-cli/aps-cli.spec.md b/specs/aps-cli/aps-cli.spec.md new file mode 100644 index 0000000..b03b482 --- /dev/null +++ b/specs/aps-cli/aps-cli.spec.md @@ -0,0 +1,106 @@ +--- +module: aps-cli +version: 1 +status: draft +files: + - Sources/aps/Aps.swift + - Sources/aps/DemoKey.swift +db_tables: [] +depends_on: + - state-store +--- + +# APS CLI + +## Purpose + +`aps` is a small Swift executable that dogfoods AppState outside SwiftUI. +It exposes a fixed demo schema through ArgumentParser subcommands so humans and +agents can get, set, watch, dump, list, and reset typed application state. + +## Public API + +### Command tree + +`Aps` is the `@main` root (`ParsableCommand`). + +| Command | Role | +|---------|------| +| `get ` | Print the current string form of a demo key. | +| `set ` | Parse and write a value, then print the stored form. | +| `watch ` | Print the current value, then print again on each change. | +| `dump` | Print all demo keys as pretty JSON (uses injected coding + clock). | +| `keys` | List demo keys with type, storage kind, and a short description. | +| `reset ` | Restore one key to its initial value and print it. | +| `reset --all` | Restore every demo key. | + +### Demo keys (`DemoKey`) + +| Key | Type | Storage | +|-----|------|---------| +| `counter` | `Int` | `State` (process-local) | +| `message` | `String` | `State` (process-local) | +| `flag` | `Bool` | `StoredState` (UserDefaults) | +| `note` | `String` | `FileState` (`~/.aps/note.json`) | + +`DemoKey` is `CaseIterable`, `ExpressibleByArgument`, and `Sendable`. + +### Errors + +`APSError` covers unknown keys, invalid values, and coding failures. CLI `set` +surfaces invalid values as ArgumentParser `ValidationError` messages. + +## Invariants + +1. The CLI entry point runs on the real main thread so AppState + `notifyChange()` assertions hold on Linux and macOS. +2. stdout for `get` / `set` / `watch` / `reset ` is only the value line(s); + help and errors use ArgumentParser defaults. +3. `State` keys are process-local; a new process must not be expected to retain + `counter` or `message`. +4. `watch` must flush each printed value immediately when stdout is not a TTY. +5. `keys` and `--help` do not mutate application state. + +## Behavioral Examples + +``` +Given a fresh process +When `aps set counter 3` runs +Then it prints `3` and exits 0. +``` + +``` +Given `aps set note hello` succeeded in process A +When process B runs `aps get note` +Then it prints `hello` (FileState persistence). +``` + +``` +Given `aps set counter nope` +When the command finishes +Then it exits non-zero with an invalid-value error naming `counter` and `Int`. +``` + +``` +Given `aps watch note` is running +When another process runs `aps set note changed` +Then the watcher prints `changed` within one poll interval. +``` + +## Error Cases + +- Unknown `DemoKey` token: ArgumentParser rejects before `run()`. +- Non-integer `counter` value: `APSError.invalidValue` -> ValidationError. +- Non-boolean `flag` value: `APSError.invalidValue` -> ValidationError. +- `reset` with neither a key nor `--all`: ValidationError. +- `reset` with both a key and `--all`: ValidationError. + +## Dependencies + +- `ArgumentParser` for the command tree +- AppState (via `StateStore`) for typed state and dependencies +- Foundation for FileHandle / RunLoop / process paths + +## Change Log + +- 1: Initial CLI contract for get/set/watch/dump/keys/reset over the fixed demo schema. diff --git a/specs/state-store/state-store.spec.md b/specs/state-store/state-store.spec.md new file mode 100644 index 0000000..f24d7b4 --- /dev/null +++ b/specs/state-store/state-store.spec.md @@ -0,0 +1,103 @@ +--- +module: state-store +version: 1 +status: draft +files: + - Sources/aps/StateStore.swift + - Sources/aps/DemoState.swift + - Sources/aps/Dependencies.swift +db_tables: [] +depends_on: [] +--- + +# State Store + +## Purpose + +`StateStore` is the AppState-facing service used by the CLI. It reads and writes +the fixed demo keys through Application extensions, injects real dependencies +with `@AppDependency`, and provides dump / watch / reset helpers suitable for +non-UI use. + +## Public API + +### Application demo surface (`DemoState.swift`) + +| Member | Kind | Initial | +|--------|------|---------| +| `Application.counter` | `State` | `0` | +| `Application.message` | `State` | `""` | +| `Application.flag` | `StoredState` | `false` | +| `Application.note` | `FileState` | `""` | +| `Application.clock` | `Dependency` | `SystemAPSClock()` | +| `Application.jsonCoding` | `Dependency` | `JSONCoding()` | + +`APSPaths.configure()` points `FileManager.defaultFileStatePath` at `~/.aps`. + +### StateStore + +| Method | Role | +|--------|------| +| `get(_:)` | Return the string form of a demo key. | +| `set(_:value:)` | Parse and write; throw `APSError.invalidValue` on bad input. | +| `reset(_:)` / `resetAll()` | Restore AppState initials (and flush UserDefaults for `flag`). | +| `dump()` | Pretty JSON snapshot using `@AppDependency` clock + jsonCoding. | +| `watchBlocking(_:pollInterval:shouldContinue:onChange:)` | Observation + RunLoop poll loop. | +| `parseBool(_:)` | Accept true/false/1/0/yes/no/on/off (case-insensitive). | + +### Dependencies (`Dependencies.swift`) + +- `APSClock` / `SystemAPSClock`: wall-clock for dump timestamps +- `JSONCoding`: shared pretty JSON encode/decode helpers + +## Invariants + +1. All mutating AppState access happens on the main thread / MainActor. +2. Writing `flag` calls `UserDefaults.standard.synchronize()` so Linux flushes + before process exit. +3. `dump()` includes every `DemoKey` plus an ISO-8601 `timestamp`. +4. `watchBlocking` emits the current value first, then subsequent distinct values. +5. Dependencies are real services, not fake stubs used only for wiring demos. + +## Behavioral Examples + +``` +Given a StateStore on a clean Application +When set(.counter, value: "7") then get(.counter) +Then the result is "7". +``` + +``` +Given set(.flag, value: "true") +When a new process constructs StateStore and get(.flag) +Then the result is "true" (StoredState persistence after synchronize). +``` + +``` +Given watchBlocking(.counter, shouldContinue: { seen.count < 2 }) +When onChange receives "1" and sets counter to "2" +Then seen equals ["1", "2"]. +``` + +``` +Given dump() after setting message to "hi" +When decoding the JSON +Then keys include message with value "hi" and a timestamp field exists. +``` + +## Error Cases + +- `set(.counter, value: "nope")` throws `APSError.invalidValue`. +- `set(.flag, value: "maybe")` throws `APSError.invalidValue`. +- JSONCoding encode/decode failures surface as `APSError.encodingFailed` / + `decodingFailed` when UTF-8 conversion fails. + +## Dependencies + +- AppState (`Application`, `State`, `StoredState`, `FileState`, `@AppDependency`) +- Observation (`withObservationTracking`) for in-process watch delivery +- Foundation (`UserDefaults`, `RunLoop`, `JSONEncoder`) + +## Change Log + +- 1: Initial StateStore / Application demo-state contract for the aps CLI. From d5f28efeb86135279b7a5ba8bed8894a2c290a35 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 18 Jul 2026 16:49:50 +0000 Subject: [PATCH 4/9] Close SpecSync CHG-0001 with active module contracts Accept the trust adoption change after fixing Public API export tables for SpecSync effective-contract checks. Add companion requirements and targeted tests; keep fledge verify native-only so Trust can own specsync. Co-authored-by: Leif --- .specsync/change-sequence.json | 2 +- .../approvals.json | 47 +++ .../change.md | 25 ++ .../context.md | 8 + .../deltas/aps-cli.md | 68 ++++ .../deltas/state-store.md | 58 +++ .../design.md | 12 + .../docs.md | 4 +- .../plan.md | 12 + .../requirements.md | 8 + .../research.md | 8 + .../state.json | 55 +++ .../tasks.md | 13 + .../testing.md | 26 ++ .../verification-attempts.json | 55 +++ .../verification.json | 381 ++++++++++++++++++ .../approvals.json | 19 - .../change.md | 24 -- .../context.md | 8 - .../design.md | 8 - .../plan.md | 8 - .../research.md | 8 - .../state.json | 50 --- .../tasks.md | 14 - .../testing.md | 8 - .../verification-attempts.json | 20 - .../verification.json | 15 - Tests/apsTests/APSTests.swift | 61 +++ fledge.toml | 6 +- specs/aps-cli/aps-cli.spec.md | 54 ++- specs/aps-cli/context.md | 3 + specs/aps-cli/requirements.md | 49 +++ specs/aps-cli/tasks.md | 6 + specs/aps-cli/testing.md | 5 + specs/state-store/context.md | 3 + specs/state-store/requirements.md | 41 ++ specs/state-store/state-store.spec.md | 53 ++- specs/state-store/tasks.md | 6 + specs/state-store/testing.md | 6 + 39 files changed, 1009 insertions(+), 248 deletions(-) create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md rename .specsync/changes/{CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli => CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/docs.md (54%) create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json create mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/approvals.json delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/change.md delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/context.md delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/design.md delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/plan.md delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/research.md delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/state.json delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/tasks.md delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/testing.md delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification-attempts.json delete mode 100644 .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification.json create mode 100644 specs/aps-cli/context.md create mode 100644 specs/aps-cli/requirements.md create mode 100644 specs/aps-cli/tasks.md create mode 100644 specs/aps-cli/testing.md create mode 100644 specs/state-store/context.md create mode 100644 specs/state-store/requirements.md create mode 100644 specs/state-store/tasks.md create mode 100644 specs/state-store/testing.md diff --git a/.specsync/change-sequence.json b/.specsync/change-sequence.json index bccaaa2..5857ddb 100644 --- a/.specsync/change-sequence.json +++ b/.specsync/change-sequence.json @@ -1,6 +1,6 @@ { "schema_version": 1, "sequence": 1, - "id": "CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli", + "id": "CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts", "acknowledged_collisions": [] } diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json new file mode 100644 index 0000000..efa4698 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json @@ -0,0 +1,47 @@ +{ + "approvals": [ + { + "gate": "definition", + "actor": "agent:cursor", + "timestamp": 1784393175, + "digest": "3155ae53d2f499b09d1c15b5bfde985844e4e0c4269a452b53e6330920594fb0", + "note": "Approved trust adoption with aps-cli/state-store semantic contracts." + }, + { + "gate": "definition", + "actor": "agent:cursor", + "timestamp": 1784393218, + "digest": "1117f027d5039903b7f17872c7749aaca939df950c2cb801db99adc668e56415", + "note": "Re-approved after export-safe deltas and requirement evidence." + }, + { + "gate": "definition", + "actor": "agent:cursor", + "timestamp": 1784393224, + "digest": "1117f027d5039903b7f17872c7749aaca939df950c2cb801db99adc668e56415", + "note": "Approved with full Public API section in deltas." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784393345, + "digest": "6006090dbf5b7d599955e51ef4fd75cf35e4b36fb1f513efb311aa8439dc7cba", + "note": "Continue without waiting for self-hosted runners; approve refreshed export-documented deltas." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784393364, + "digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "note": "Re-approve after switching existing REQs to MODIFIED; ADDED only REQ-aps-cli-005." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784393368, + "digest": "6d19a3078f062938ee3e14692d1ed6694ceb70bdc794146a86108cc8c1de509b", + "note": "Accept after local verify green; CI awaits macOS self-hosted runners." + } + ], + "reopenings": [] +} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md new file mode 100644 index 0000000..2a2252c --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md @@ -0,0 +1,25 @@ +--- +id: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts +state: accepted +type: migration +base_commit: f4bd6f9adbc83a4ebaa8760a08f1f699566638f9 +--- + +# Adopt CorvidLabs trust and establish aps module contracts + +## Intent + +Adopt CorvidLabs trust and establish aps module contracts + +## Affected Canonical Specs + +- `aps-cli` +- `state-store` + +## Acceptance Criteria + +- Trust config and self-hosted macOS CI are committed; aps-cli and state-store active contracts pass specsync check; fledge verify lane builds tests and smokes; targeted unit tests cover reset/keys validation and flag persistence + +## No-spec Rationale + +Not applicable diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md new file mode 100644 index 0000000..19c0a95 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts +artifact: context +--- + +# Context + +aps-cli dogfoods AppState as a Swift CLI. This migration adopts the CorvidLabs trust toolchain, establishes canonical module contracts, and keeps CI on macOS self-hosted runners while the repository is private. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md new file mode 100644 index 0000000..ece9fd3 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md @@ -0,0 +1,68 @@ +# APS CLI contract introduction + +## ADDED + +### REQUIREMENT REQ-aps-cli-005 + +`APSError` SHALL cover `unknownKey`, `invalidValue`, `encodingFailed`, and `decodingFailed`. + +Acceptance Criteria +- Each case is reachable from CLI or StateStore coding paths. +- `description` is suitable for ValidationError bridging. + +## MODIFIED + +### REQUIREMENT REQ-aps-cli-001 + +The CLI SHALL expose get, set, watch, dump, keys, and reset over the fixed `DemoKey` schema covering `counter`, `message`, `flag`, and `note`. + +Acceptance Criteria +- `aps --help` lists those subcommands. +- `DemoKey` includes only those four cases and exposes `storage`, `valueType`, `helpSummary`, and `detail`. + +### REQUIREMENT REQ-aps-cli-002 + +`set` SHALL reject values that cannot parse to the key's type and exit non-zero via `APSError.invalidValue`. + +Acceptance Criteria +- Non-integer `counter` values fail with an invalid-value message. +- Non-boolean `flag` values fail with an invalid-value message. +- `APSError.description` names the key and expected type. + +### REQUIREMENT REQ-aps-cli-003 + +Process-local `State` keys SHALL not be required to persist across process boundaries. + +Acceptance Criteria +- `counter` and `message` are documented and tested as process-local. +- `flag` (`StoredState`) and `note` (`FileState`) persist across processes after a successful set. + +### REQUIREMENT REQ-aps-cli-004 + +`watch` SHALL print the current value first and flush subsequent distinct values promptly. + +Acceptance Criteria +- The first emitted line is the current value. +- Non-TTY stdout still surfaces each change without waiting for process exit. + +### SPEC SECTION Public API + +| Export | Description | +|--------|-------------| +| `DemoKey` | Fixed schema enum (`CaseIterable`, `ExpressibleByArgument`, `Sendable`). | +| `APSError` | Typed CLI/domain errors. | +| `counter` | Int key stored in AppState `State`. | +| `message` | String key stored in AppState `State`. | +| `flag` | Bool key stored in AppState `StoredState`. | +| `note` | String key stored in AppState `FileState`. | +| `unknownKey` | Unknown demo key token. | +| `invalidValue` | Value could not parse for the key type. | +| `encodingFailed` | UTF-8 JSON encode failure. | +| `decodingFailed` | UTF-8 JSON decode failure. | +| `storage` | Human storage kind (`State` / `StoredState` / `FileState`). | +| `valueType` | Human value type (`Int` / `String` / `Bool`). | +| `helpSummary` | Tab-separated key/type/storage columns for `keys`. | +| `detail` | One-line description for `keys`. | +| `description` | Actionable error text for humans and ValidationError bridging. | + +Command tree (informational): `Aps` is the `@main` root (`ParsableCommand`) with get, set, watch, dump, keys, and reset / reset --all. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md new file mode 100644 index 0000000..8e5ced9 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md @@ -0,0 +1,58 @@ +# State Store contract introduction + +## MODIFIED + +### REQUIREMENT REQ-state-store-001 + +`StateStore` SHALL read and write demo keys through AppState Application extensions on the main actor via `init`, `get`, and `set`. + +Acceptance Criteria +- `get`/`set` round-trip `counter`, `message`, `flag`, and `note`. +- Mutating paths are MainActor-isolated. + +### REQUIREMENT REQ-state-store-002 + +`StateStore` SHALL inject real `APSClock` / `SystemAPSClock` (`now`) and `JSONCoding` (`encodePretty`, `decode`) dependencies for `dump` output. + +Acceptance Criteria +- `dump` JSON includes every `DemoKey` and a timestamp. +- Dependencies are loaded via `Application.dependency` / `@AppDependency`. + +### REQUIREMENT REQ-state-store-003 + +Writing `flag` SHALL flush UserDefaults so Linux short-lived processes persist StoredState; `reset` / `resetAll` restore initials. + +Acceptance Criteria +- After `set(.flag, "true")`, a new `StateStore` instance observes true. +- `reset(.flag)` restores false and flushes. + +### REQUIREMENT REQ-state-store-004 + +`watchBlocking` SHALL combine Observation with RunLoop polling and honor `shouldContinue`; `parseBool` accepts common truthy/falsey tokens. + +Acceptance Criteria +- In-process `State` mutations are observed. +- `FileState` mutations performed during the loop are observed. +- `shouldContinue` false stops the loop without requiring Ctrl-C. + +### SPEC SECTION Public API + +| Export | Description | +|--------|-------------| +| `StateStore` | MainActor AppState facade used by the CLI. | +| `APSClock` | Clock protocol for dump timestamps. | +| `SystemAPSClock` | Production `APSClock` backed by `Date()`. | +| `JSONCoding` | Shared pretty JSON helpers. | +| `init` | Configures FileState path and loads clock/jsonCoding dependencies. | +| `get` | Return the string form of a demo key. | +| `set` | Parse and write; throw `APSError.invalidValue` on bad input. | +| `reset` | Restore one key to its AppState initial value. | +| `resetAll` | Restore every demo key. | +| `dump` | Pretty JSON snapshot using `@AppDependency` clock + jsonCoding. | +| `watchBlocking` | Observation + RunLoop poll loop with `shouldContinue`. | +| `parseBool` | Accept true/false/1/0/yes/no/on/off (case-insensitive). | +| `now` | Current `Date` from an `APSClock`. | +| `encodePretty` | Encode an `Encodable` value as pretty UTF-8 JSON text. | +| `decode` | Decode a `Decodable` value from UTF-8 JSON text. | + +Application demo surface (informational): `Application.counter` / `message` / `flag` / `note` / `clock` / `jsonCoding`, with `APSPaths.configure()` pointing FileState at `~/.aps`. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md new file mode 100644 index 0000000..b35b1e2 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md @@ -0,0 +1,12 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts +artifact: design +--- + +# Design + +- Standard Trust profile with soft provenance +- Canonical specs: aps-cli (CLI surface) and state-store (AppState access) +- Semantic deltas introduce stable REQ-IDs for each public behavior +- fledge verify: build, test, smoke, and specsync check +- CI/Trust workflows: runs-on [self-hosted, macOS] diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/docs.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md similarity index 54% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/docs.md rename to .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md index e45db85..844c90c 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/docs.md +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md @@ -1,8 +1,8 @@ --- -change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli +change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts artifact: docs --- # Docs -README documents commands, trust files, and the private-repo self-hosted runner policy. AGENTS.md carries the managed CorvidLabs trust toolchain block. +README documents commands, trust files, and the private-repo self-hosted runner policy. AGENTS.md carries the managed CorvidLabs trust toolchain block. Module contracts live under specs/. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md new file mode 100644 index 0000000..4220a38 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md @@ -0,0 +1,12 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts +artifact: plan +--- + +# Plan + +1. Commit trust/spec-sync/augur/attest config and AGENTS.md markers +2. Author and activate aps-cli and state-store specs with companions +3. Apply semantic deltas establishing ownership REQ-IDs +4. Expand targeted tests and add spec to the fledge verify lane +5. Verify, accept, and archive this change; record attest provenance diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md new file mode 100644 index 0000000..a1cb4dc --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts +artifact: requirements +--- + +# Requirements + +See semantic deltas under deltas/ for REQ-aps-cli-* and REQ-state-store-* introductions applied on acceptance. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md new file mode 100644 index 0000000..31a0896 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts +artifact: research +--- + +# Research + +Trust 1 composes fledge, SpecSync 5, augur, and attest. SpecSync acceptance requires production sources to have deterministic canonical ownership through affected specs and semantic deltas. Self-hosted macOS runners are preferred while private; hosted runners succeeded earlier for Linux/macOS smoke. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json new file mode 100644 index 0000000..69bed72 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json @@ -0,0 +1,55 @@ +{ + "schema_version": 1, + "id": "CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts", + "slug": "adopt-corvidlabs-trust-and-establish-aps-module-contracts", + "title": "Adopt CorvidLabs trust and establish aps module contracts", + "description": "Adopt CorvidLabs trust and establish aps module contracts", + "kind": "migration", + "state": "accepted", + "canonical_applied": true, + "base_commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", + "created_at": 1784393134, + "updated_at": 1784393368, + "affected_specs": [ + "aps-cli", + "state-store" + ], + "affected_paths": [ + ".github/workflows/", + ".specsync/", + "specs/", + "Sources/", + "Tests/", + "Scripts/", + "fledge.toml", + ".trust.toml", + ".augur.toml", + ".attest.json", + "AGENTS.md", + "CLAUDE.md", + "README.md", + "Package.swift", + "Package.resolved", + ".gitignore" + ], + "no_spec_change": false, + "no_spec_change_rationale": null, + "acceptance_criteria": [ + "Trust config and self-hosted macOS CI are committed; aps-cli and state-store active contracts pass specsync check; fledge verify lane builds tests and smokes; targeted unit tests cover reset/keys validation and flag persistence" + ], + "selected_artifacts": [ + "context", + "research", + "design", + "plan", + "tasks", + "testing", + "docs", + "requirements" + ], + "dependencies": [], + "answers": { + "architecture_risk": "no", + "public_contract": "yes" + } +} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md new file mode 100644 index 0000000..c0b899b --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md @@ -0,0 +1,13 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts +artifact: tasks +--- + +# Tasks + +- [x] Trust config, AGENTS.md, self-hosted macOS CI/Trust workflows +- [x] SpecSync policy, registry, and active module specs +- [x] Semantic deltas for aps-cli and state-store +- [x] Targeted unit tests (reset/keys validation, flag persistence) +- [x] Keep verify lane native-only; expose `fledge run check` with specsync +- [x] Local verify evidence recorded for acceptance diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md new file mode 100644 index 0000000..c37ab9b --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md @@ -0,0 +1,26 @@ +--- +change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts +artifact: testing +--- + +# Testing + +## Requirement evidence + +| Requirement | Evidence | +|-------------|----------| +| REQ-aps-cli-001 | `testDemoKeyMetadata`, `testDemoKeyHelpSummaryFormat`, `Scripts/smoke.sh` keys | +| REQ-aps-cli-002 | `testInvalidCounterValue`, `testInvalidFlagValue`, `testAPSErrorDescriptionsAreActionable` | +| REQ-aps-cli-003 | `testProcessLocalStateKeysDoNotClaimCrossProcessPersistence`, `testFlagPersistsAcrossStateStoreInstances`, smoke flag/note | +| REQ-aps-cli-004 | `testWatchDetectsInProcessStateChange`, `testWatchDetectsFileStateChange` | +| REQ-aps-cli-005 | `testAPSErrorDescriptionsAreActionable`, `testInvalidCounterValue` | +| REQ-state-store-001 | `testCounterRoundTrip`, `testMessageAndFlagRoundTrip`, `testNoteFileStateRoundTrip` | +| REQ-state-store-002 | `testDumpIncludesKeysAndUsesDependency`, `testJSONCodingDependency`, `testClockDependencyIsInjectable` | +| REQ-state-store-003 | `testFlagPersistsAcrossStateStoreInstances`, `testResetRestoresInitialValues`, `testResetAll` | +| REQ-state-store-004 | `testWatchDetectsInProcessStateChange`, `testWatchDetectsFileStateChange`, `testParseBool` | + +## Gate evidence + +- `swift test` (18 tests) +- `./Scripts/smoke.sh` +- `fledge lanes run verify` diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json new file mode 100644 index 0000000..f818685 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json @@ -0,0 +1,55 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1784393349, + "commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", + "contract_digest": "6006090dbf5b7d599955e51ef4fd75cf35e4b36fb1f513efb311aa8439dc7cba", + "workspace_digest": "c8511495beb59a1886f889207c2367c0cad3fa3efcba98a29d28ef1a1c5ddcd0", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-001", + "REQ-aps-cli-002", + "REQ-aps-cli-003", + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-002", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + { + "timestamp": 1784393368, + "commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", + "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "workspace_digest": "c8511495beb59a1886f889207c2367c0cad3fa3efcba98a29d28ef1a1c5ddcd0", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-001", + "REQ-aps-cli-002", + "REQ-aps-cli-003", + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-002", + "REQ-state-store-003", + "REQ-state-store-004" + ] + } + ] +} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json new file mode 100644 index 0000000..8682e3b --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json @@ -0,0 +1,381 @@ +{ + "timestamp": 1784393368, + "commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", + "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "workspace_digest": "c8511495beb59a1886f889207c2367c0cad3fa3efcba98a29d28ef1a1c5ddcd0", + "acceptance_input_digest": "e410fc1465ce16aa200e9d509f4455dc3cea215a8640e82d20608be2d58745c2", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": ".attest.json", + "kind": "file", + "mode": 33188, + "payload_digest": "fda17571040ce10c378e009859f92cc33afd67b5c62d3f96510bf9e6e5de0a9f", + "entry_digest": "9d185be1f08f917f1162191bbd90ca325f047bec1cda66f2fc6d0737c08da1ab", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".augur.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "17f6ad5b84b4db012f0e3f398a96a478c1324fd47e72e1dd2a13c7cf9a432983", + "entry_digest": "bac13c952da05292bdd0af5849aad9d9def3ae5afc830fa42b6914b2fd874beb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/ci.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "1f310d5d11b4466aedf85aac75d7db13b07d564f1e38e2f596defb8cf2f06d1c", + "entry_digest": "9abaefb404d6bb884367be7ea7524e890c9bab326c810c0985569c35a83418e7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/trust.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "f4fad2f8914de3e6285b1afce3dc3ebe624e657aecc3bb2312fd6c3003a76f7f", + "entry_digest": "a1f5ca04418295d7d3919880416b2166a40ca6b0ac527a83458ecf51d26d2788", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "30d23b531c3fcb3e46c413c3d06d3c2848bb273aaf86abdee660e201ed9519a9", + "entry_digest": "8c2aa3eee1fa32d85bddb1f5daf626a0a97ce920f434cd2ec57050fe1623867a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/.gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "a3129d6f93250ade8dbacfc73bc7eeae0cc47c2f7032142ca47cb4f1ffb2483e", + "entry_digest": "9badbf40b83d05f58bafda0fc2cafccfe726e4da7e6e67ef513e822989e13f04", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/change-sequence.json", + "kind": "file", + "mode": 33188, + "payload_digest": "1f95d9c5ccca97dabb0fa17a4d2b2491023b263fb475e5a03e784eeb63f7232a", + "entry_digest": "f4b667fec7bde996c7c0f9b31f7ea84ddef37f171371f3e0084c0bb9a66978af", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/config.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "54a83f6a4a252649bac390d2e936aa0815711fba86b6bfc8ea8fff2fffdfd29b", + "entry_digest": "e60f979233a7db75ce63f4ef42d6f1f7676ad1655a438b9baf78558aba60ec3e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/registry.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "c423be1a5cf87318f85dc252fe0acd1c1486c5224ddc2d8e19bea1ac9c69c820", + "entry_digest": "7e1f068900ced849b8d1028ca40165fbdc5280ae7f53452f0e57e2710d895848", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/sdd.json", + "kind": "file", + "mode": 33188, + "payload_digest": "2d5fb3058b1ee4ce584c3cda9410c193c4893e272ed459205e58bfde06afc7b0", + "entry_digest": "8c6b11fc5787eb04e7ee651eb15fbf98fc3ea22db37e65423e3d75f99c09df19", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/version", + "kind": "file", + "mode": 33188, + "payload_digest": "23b6867924dfeb9cf532753438dc919669bf93ad88215e11c15630a4acbf4299", + "entry_digest": "339b5f88be30302336707baa5dab61fd4b324d04e495d3bb772cf893fb4f73bc", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".trust.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "6284ced27613c8e2dd8266ffd1668f021cb24e1edb6ccd79c9ade86032c09ce8", + "entry_digest": "7cdd9144620ced58d9ac48ee7d2b8563f5564f1ae2db02a22e7eed781963257e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "AGENTS.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a671dd50eea50f115e6f9abd554e5a8ad7e520208fec5c4bd540c4f3a07ef807", + "entry_digest": "c321960d8ebbf18c2833c8f8b7fe413d6f0e349b424bf2b296a4da7a26316750", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "CLAUDE.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e2df5028858a540821e4a666297d536a14bf598d48afe6c44df921b0f1ddbf32", + "entry_digest": "6930540d6a42ffd8c849bdf10eaf69c3f231cf5e824c9e6f0e694d3edb91bda3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.resolved", + "kind": "file", + "mode": 33188, + "payload_digest": "12eea9fa129e151eaffdc230a234293407f0e3a99c52f15597c72e4e591c0e1e", + "entry_digest": "554d48ebe132641edab54e1d89d163cc2534521a9f41750ed5bd8582723a2d28", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", + "entry_digest": "0b185dd498f42e05a6cc8c2447d547432f4c40000c5dc26f17fe0fc7ae21d6cb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "247d8f2d3f67cf9a7c3641ad26bc37a016fa4c7a637f8d0349864f85de6e6bad", + "entry_digest": "464275632b4b92467210ce1683caa823bd308fcc98cedf860e53da9e37d563a6", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Scripts/smoke.sh", + "kind": "file", + "mode": 33261, + "payload_digest": "5947d02b95d6205d63beca54876398d81226d0d4796b4234b646a3b919f08b4c", + "entry_digest": "a847aedf94fa22e35460140f14bdd4be567c550ddc2d20ade0f672329f3efbd7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Sources/aps/Aps.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "17c9cb972eec5b29d19adf9ea64e125ef03d8bbfb8f5115e438a309c0a1d4316", + "entry_digest": "19304c7bb4daa894ed568d6ead0153390bc7011acf03d1d08addf0b3ac13e4a4", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoKey.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f973ce1f86e31efd412a76938db78bbd36b01b6ee7dbb48a9865edb569917380", + "entry_digest": "5d391ca2c3462528b91a83888a6b09484f850995b504d01f61a31c91ec3a80db", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoState.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "036eed2ac58afdf87b30938911658abe74888fd3ca2c6a63869de3f5f2701125", + "entry_digest": "7dda9ef80f141fffd93dc5a6dfa9c41b5f2c7ce28265341e764b72269c687595", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/Dependencies.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "635340259dcd618bf5099e07dad823f72f4517f6a2762ec1e6b67965221ccef2", + "entry_digest": "637ab3fca33111ebb5f145cdd632e7a6412e99d88d08e3890ab1cc3edc54c736", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/StateStore.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "d6773947e8268bac77da4c323b541ef5fe514939d4ef0cafd74ecbd3a4a3ece3", + "entry_digest": "190b8e0e4aa74797e09b64e1576b3ddb5b57dcf991cd71a5951fe3e606803c08", + "owners": [ + "state-store" + ] + }, + { + "path": "Tests/apsTests/APSTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "55ac9e3657a48995bad11dfe75de46f9e367b3cf0a0250b90d685392d4e09a15", + "entry_digest": "388f64f61823bb9f78051c74227da3839f15955a8bae50b579003c5bc13fe78e", + "owners": [ + "@exact:test" + ] + }, + { + "path": "fledge.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "f69feb965265eb9481197160885409a03d0eb367149a2955c7b17a98dee9ba4e", + "entry_digest": "4994cce91eb6ed15dcf039ff4ce7194b901fe8e5ef33905503817173f42b6560", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/aps-cli/aps-cli.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "f5cc6d9e1f1f328b100b826707470577669dc24e46cc4f8f9d98164a2f0339a8", + "entry_digest": "07206127871185e01418a2f11a620743fcb70666abdcbcc895a8d0f8a88fd536", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "57d3395961e0cbe4ca7c02b638cd0e5da34214f3fd0c1342914eec6cccd3ff8c", + "entry_digest": "ccba3dc943b3128bef61641fe7c5b57c14393ad0e009353b6f86cd0446890fbf", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "6f0a119928aaded71476b059b3950aea3dfcc80d32a377857ed4b0ad5b1240a1", + "entry_digest": "fb8e378328b81db7a39be58a5e31c8627a99a63f834e92bc65062718c7caa69a", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "d4310391e8703dbcf632a37901ed8c65d0675e5830284325269e7fe371b6094f", + "entry_digest": "5e3171593d0abe547a27788401056cfce4f911383ef4526cc3f3bdc3150361e8", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "d1b40f1198fb2b23d3452450afb5c84748d95c38efd81529213cb75cdc5071c9", + "entry_digest": "dab7bdb784204ee22cad510b0de8008ea539ca747419f3c818003deae04cbbd3", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/state-store/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "35090a0e0d4e0b10ac64cccd5f6346b7380ff6a5d6180ec732f12eb554c00bf7", + "entry_digest": "3df91075712a9b76bb0d810a76ab3bcb75f2518680c69356c843a166a2934691", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "1e877f271ce3b3794a5019b4321b6bf971ddf08bdf400a2e5405587c35a8f606", + "entry_digest": "92c4d1f84ee0874655e25e66422faa80470e7e0512e51124755fb6ed36ea6ef8", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/state-store.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "1531480af30af3a268a1234b78346bced142443d04cd1e67b1488a2541404084", + "entry_digest": "875548708b0830fbce9aa616293cdacf7e89f2ac23d391aa85057fa8cf5ab24d", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "4a931c764c1b83ba70ead17a33f55aaf4356a367f600f10724b963b9d1c6ca92", + "entry_digest": "bd414350cad0fccf90e0acd9da163a4e7d4242a653bd9d6b475cd58530858666", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "159bf0c984c3490f5f7da8704b9153f41f8bc2ced3ea43246123a72d5a3f7783", + "entry_digest": "dd51d33d0d6928c2f90459f02abe826ee4a95490baefcf4ace149a9fb2f47c91", + "owners": [ + "state-store" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-001", + "REQ-aps-cli-002", + "REQ-aps-cli-003", + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-002", + "REQ-state-store-003", + "REQ-state-store-004" + ] +} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/approvals.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/approvals.json deleted file mode 100644 index 97ac732..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/approvals.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "approvals": [ - { - "gate": "definition", - "actor": "agent:cursor", - "timestamp": 1784392032, - "digest": "fa4a28bbc4403e69844dd6de124cc599c5cf7fa0047bdb9107b02e9135eb99e7", - "note": "Approved CorvidLabs trust adoption for private aps-cli with self-hosted macOS CI." - }, - { - "gate": "definition", - "actor": "agent:cursor", - "timestamp": 1784392047, - "digest": "0b7711988c6850f3a9f0bf39151dd32f8fdb09821e0c214c26aefe3b8599565c", - "note": "Re-approved after completing migration tasks." - } - ], - "reopenings": [] -} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/change.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/change.md deleted file mode 100644 index f69f326..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/change.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -id: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli -state: implementing -type: migration -base_commit: 4340cdf1ea69e060946f4e418e2b0ea02c7e9144 ---- - -# Adopt CorvidLabs trust toolchain for the private aps CLI - -## Intent - -Adopt CorvidLabs trust toolchain for the private aps CLI - -## Affected Canonical Specs - -- None - -## Acceptance Criteria - -- fledge verify lane builds tests and smokes aps; SpecSync registry lists aps-cli and state-store; Trust config and AGENTS.md markers are committed; CI and Trust workflows run on self-hosted macOS only - -## No-spec Rationale - -Bootstrap governance, CI, and committed module contracts without applying semantic deltas; aps-cli and state-store specs are authored as canonical companions in the same PR. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/context.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/context.md deleted file mode 100644 index 4d05439..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/context.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli -artifact: context ---- - -# Context - -aps-cli is a private Swift package that dogfoods AppState as a CLI. This migration wires the CorvidLabs trust toolchain and moves CI onto macOS self-hosted runners while the repository remains private. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/design.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/design.md deleted file mode 100644 index e8c0ebc..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/design.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli -artifact: design ---- - -# Design - -Keep a standard Trust profile with soft provenance. Commit module specs for aps-cli and state-store as canonical companions. CI and Trust workflows both use runs-on: [self-hosted, macOS]. fledge lanes.verify runs build, test, and smoke. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/plan.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/plan.md deleted file mode 100644 index 1f905da..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/plan.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli -artifact: plan ---- - -# Plan - -1. Commit trust config and SpecSync policy. 2. Author module specs. 3. Replace hosted Linux/macOS workflows with self-hosted CI and Trust. 4. Approve and start this migration change. 5. Confirm runners pick up checks on the PR. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/research.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/research.md deleted file mode 100644 index 7b4d1c0..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/research.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli -artifact: research ---- - -# Research - -CorvidLabs Trust 1 composes fledge, SpecSync 5, augur, and attest. The corvid-stack template and https://corvidlabs.xyz/integrate/ define the adoption shape. Self-hosted macOS runners are appropriate for private repos; hosted runners should be restored before public fork PR exposure. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/state.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/state.json deleted file mode 100644 index 17d0034..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/state.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "schema_version": 1, - "id": "CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli", - "slug": "adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli", - "title": "Adopt CorvidLabs trust toolchain for the private aps CLI", - "description": "Adopt CorvidLabs trust toolchain for the private aps CLI", - "kind": "migration", - "state": "verifying", - "base_commit": "4340cdf1ea69e060946f4e418e2b0ea02c7e9144", - "created_at": 1784392021, - "updated_at": 1784392050, - "affected_specs": [], - "affected_paths": [ - ".github/workflows/", - ".specsync/", - "specs/", - "Sources/", - "Tests/", - "Scripts/", - "fledge.toml", - ".trust.toml", - ".augur.toml", - ".attest.json", - "AGENTS.md", - "CLAUDE.md", - "README.md", - "Package.swift", - "Package.resolved", - ".gitignore" - ], - "no_spec_change": true, - "no_spec_change_rationale": "Bootstrap governance, CI, and committed module contracts without applying semantic deltas; aps-cli and state-store specs are authored as canonical companions in the same PR.", - "acceptance_criteria": [ - "fledge verify lane builds tests and smokes aps; SpecSync registry lists aps-cli and state-store; Trust config and AGENTS.md markers are committed; CI and Trust workflows run on self-hosted macOS only" - ], - "selected_artifacts": [ - "context", - "research", - "design", - "plan", - "tasks", - "testing", - "docs" - ], - "dependencies": [], - "answers": { - "architecture_risk": "no", - "public_contract": "no" - } -} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/tasks.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/tasks.md deleted file mode 100644 index f38e17c..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/tasks.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli -artifact: tasks ---- - -# Tasks - -- [x] Add fledge.toml verify lane (build/test/smoke) -- [x] Add .trust.toml, .augur.toml, .attest.json -- [x] Add SpecSync config, registry, SDD policy, version pin -- [x] Author aps-cli and state-store specs -- [x] Add AGENTS.md managed trust block and CLAUDE.md pointer -- [x] Move CI/Trust workflows to [self-hosted, macOS] -- [x] Pass local `fledge trust verify` (progressive provenance) diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/testing.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/testing.md deleted file mode 100644 index 3c4ad30..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/testing.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli -artifact: testing ---- - -# Testing - -Local: fledge lanes run verify, swift test, Scripts/smoke.sh, fledge trust doctor. CI: CI workflow smokes the release binary; Trust workflow runs CorvidLabs/trust@v1 and greps AGENTS.md markers. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification-attempts.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification-attempts.json deleted file mode 100644 index 2ef0da2..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification-attempts.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "schema_version": 1, - "attempts": [ - { - "timestamp": 1784392050, - "commit": "4340cdf1ea69e060946f4e418e2b0ea02c7e9144", - "contract_digest": "0b7711988c6850f3a9f0bf39151dd32f8fdb09821e0c214c26aefe3b8599565c", - "workspace_digest": "6b67f53d36cc2d782bc41d6f53e5314904ed19666d1c475d87f988f74181134c", - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [] - } - ] -} diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification.json deleted file mode 100644 index 277d7e6..0000000 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-toolchain-for-the-private-aps-cli/verification.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "timestamp": 1784392050, - "commit": "4340cdf1ea69e060946f4e418e2b0ea02c7e9144", - "contract_digest": "0b7711988c6850f3a9f0bf39151dd32f8fdb09821e0c214c26aefe3b8599565c", - "workspace_digest": "6b67f53d36cc2d782bc41d6f53e5314904ed19666d1c475d87f988f74181134c", - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [] -} diff --git a/Tests/apsTests/APSTests.swift b/Tests/apsTests/APSTests.swift index e97a507..f86c08a 100644 --- a/Tests/apsTests/APSTests.swift +++ b/Tests/apsTests/APSTests.swift @@ -179,4 +179,65 @@ final class APSTests: XCTestCase { let before = clock.now XCTAssertLessThanOrEqual(before.timeIntervalSinceNow, 0) } + + @MainActor + func testInvalidFlagValue() async { + let store = StateStore() + do { + try store.set(.flag, value: "maybe") + XCTFail("Expected invalid value error") + } catch let error as APSError { + XCTAssertEqual(error, .invalidValue(key: .flag, value: "maybe")) + } catch { + XCTFail("Unexpected error: \(error)") + } + } + + @MainActor + func testFlagPersistsAcrossStateStoreInstances() async throws { + let writer = StateStore() + try writer.set(.flag, value: "true") + XCTAssertEqual(writer.get(.flag), "true") + + let reader = StateStore() + XCTAssertEqual(reader.get(.flag), "true") + + reader.reset(.flag) + XCTAssertEqual(StateStore().get(.flag), "false") + } + + @MainActor + func testProcessLocalStateKeysDoNotClaimCrossProcessPersistence() async throws { + // Document the contract: State keys are process-local. A fresh Application + // reset (as in setUp) restores initials; this test locks that expectation. + let store = StateStore() + try store.set(.counter, value: "99") + try store.set(.message, value: "ephemeral") + XCTAssertEqual(store.get(.counter), "99") + XCTAssertEqual(store.get(.message), "ephemeral") + + Application.reset(\.counter) + Application.reset(\.message) + XCTAssertEqual(store.get(.counter), "0") + XCTAssertEqual(store.get(.message), "") + } + + func testDemoKeyHelpSummaryFormat() { + for key in DemoKey.allCases { + let parts = key.helpSummary.split(separator: "\t") + XCTAssertEqual(parts.count, 3, "Expected key/type/storage columns for \(key)") + XCTAssertEqual(String(parts[0]), key.rawValue) + XCTAssertFalse(key.detail.isEmpty) + } + } + + func testAPSErrorDescriptionsAreActionable() { + let invalid = APSError.invalidValue(key: .counter, value: "nope") + XCTAssertTrue(invalid.description.contains("counter")) + XCTAssertTrue(invalid.description.contains("Int")) + + let unknown = APSError.unknownKey("wat") + XCTAssertTrue(unknown.description.contains("wat")) + XCTAssertTrue(unknown.description.contains("counter")) + } } diff --git a/fledge.toml b/fledge.toml index d2d56a7..0917757 100644 --- a/fledge.toml +++ b/fledge.toml @@ -6,9 +6,11 @@ build = "swift build" test = "swift test" release-build = "swift build -c release" smoke = "./Scripts/smoke.sh" +# Keep specsync out of lanes.verify: Trust/SpecSync run it as a top-level gate +# so verification commands cannot recurse into specsync check. spec = "specsync check" -check = "fledge run build && fledge run test && fledge run smoke" +check = "fledge run build && fledge run test && fledge run smoke && fledge run spec" [lanes.verify] -description = "Build, test, and smoke aps (the single quality gate)" +description = "Native quality gate (build, test, smoke)" steps = ["build", "test", "smoke"] diff --git a/specs/aps-cli/aps-cli.spec.md b/specs/aps-cli/aps-cli.spec.md index b03b482..158ea1c 100644 --- a/specs/aps-cli/aps-cli.spec.md +++ b/specs/aps-cli/aps-cli.spec.md @@ -1,7 +1,7 @@ --- module: aps-cli -version: 1 -status: draft +version: 3 +status: active files: - Sources/aps/Aps.swift - Sources/aps/DemoKey.swift @@ -20,35 +20,25 @@ agents can get, set, watch, dump, list, and reset typed application state. ## Public API -### Command tree - -`Aps` is the `@main` root (`ParsableCommand`). - -| Command | Role | -|---------|------| -| `get ` | Print the current string form of a demo key. | -| `set ` | Parse and write a value, then print the stored form. | -| `watch ` | Print the current value, then print again on each change. | -| `dump` | Print all demo keys as pretty JSON (uses injected coding + clock). | -| `keys` | List demo keys with type, storage kind, and a short description. | -| `reset ` | Restore one key to its initial value and print it. | -| `reset --all` | Restore every demo key. | - -### Demo keys (`DemoKey`) - -| Key | Type | Storage | -|-----|------|---------| -| `counter` | `Int` | `State` (process-local) | -| `message` | `String` | `State` (process-local) | -| `flag` | `Bool` | `StoredState` (UserDefaults) | -| `note` | `String` | `FileState` (`~/.aps/note.json`) | - -`DemoKey` is `CaseIterable`, `ExpressibleByArgument`, and `Sendable`. - -### Errors - -`APSError` covers unknown keys, invalid values, and coding failures. CLI `set` -surfaces invalid values as ArgumentParser `ValidationError` messages. +| Export | Description | +|--------|-------------| +| `DemoKey` | Fixed schema enum (`CaseIterable`, `ExpressibleByArgument`, `Sendable`). | +| `APSError` | Typed CLI/domain errors. | +| `counter` | Int key stored in AppState `State`. | +| `message` | String key stored in AppState `State`. | +| `flag` | Bool key stored in AppState `StoredState`. | +| `note` | String key stored in AppState `FileState`. | +| `unknownKey` | Unknown demo key token. | +| `invalidValue` | Value could not parse for the key type. | +| `encodingFailed` | UTF-8 JSON encode failure. | +| `decodingFailed` | UTF-8 JSON decode failure. | +| `storage` | Human storage kind (`State` / `StoredState` / `FileState`). | +| `valueType` | Human value type (`Int` / `String` / `Bool`). | +| `helpSummary` | Tab-separated key/type/storage columns for `keys`. | +| `detail` | One-line description for `keys`. | +| `description` | Actionable error text for humans and ValidationError bridging. | + +Command tree (informational): `Aps` is the `@main` root (`ParsableCommand`) with get, set, watch, dump, keys, and reset / reset --all. ## Invariants @@ -104,3 +94,5 @@ Then the watcher prints `changed` within one poll interval. ## Change Log - 1: Initial CLI contract for get/set/watch/dump/keys/reset over the fixed demo schema. +- 2: Explicit export inventory for SpecSync active-contract checks (`DemoKey`, `APSError`). +| 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | diff --git a/specs/aps-cli/context.md b/specs/aps-cli/context.md new file mode 100644 index 0000000..58a8c1e --- /dev/null +++ b/specs/aps-cli/context.md @@ -0,0 +1,3 @@ +# Context - APS CLI + +The executable surface dogfoods AppState outside SwiftUI. It stays small: fixed demo keys, no plugin system, no network API. diff --git a/specs/aps-cli/requirements.md b/specs/aps-cli/requirements.md new file mode 100644 index 0000000..6ddc286 --- /dev/null +++ b/specs/aps-cli/requirements.md @@ -0,0 +1,49 @@ +--- +spec: aps-cli.spec.md +--- + +# Requirements - APS CLI + +## Functional + +### REQ-aps-cli-001 + +The CLI SHALL expose get, set, watch, dump, keys, and reset over the fixed `DemoKey` schema covering `counter`, `message`, `flag`, and `note`. + +Acceptance Criteria +- `aps --help` lists those subcommands. +- `DemoKey` includes only those four cases and exposes `storage`, `valueType`, `helpSummary`, and `detail`. + +### REQ-aps-cli-002 + +`set` SHALL reject values that cannot parse to the key's type and exit non-zero via `APSError.invalidValue`. + +Acceptance Criteria +- Non-integer `counter` values fail with an invalid-value message. +- Non-boolean `flag` values fail with an invalid-value message. +- `APSError.description` names the key and expected type. + +### REQ-aps-cli-003 + +Process-local `State` keys SHALL not be required to persist across process boundaries. + +Acceptance Criteria +- `counter` and `message` are documented and tested as process-local. +- `flag` (`StoredState`) and `note` (`FileState`) persist across processes after a successful set. + +### REQ-aps-cli-004 + +`watch` SHALL print the current value first and flush subsequent distinct values promptly. + +Acceptance Criteria +- The first emitted line is the current value. +- Non-TTY stdout still surfaces each change without waiting for process exit. + +### REQ-aps-cli-005 + +`APSError` SHALL cover `unknownKey`, `invalidValue`, `encodingFailed`, and `decodingFailed`. + +Acceptance Criteria +- Each case is reachable from CLI or StateStore coding paths. +- `description` is suitable for ValidationError bridging. + diff --git a/specs/aps-cli/tasks.md b/specs/aps-cli/tasks.md new file mode 100644 index 0000000..23a3def --- /dev/null +++ b/specs/aps-cli/tasks.md @@ -0,0 +1,6 @@ +# Tasks - APS CLI + +- [x] ArgumentParser command tree for get/set/watch/dump/keys/reset +- [x] DemoKey fixed schema with storage metadata +- [x] Main-thread AppState access for Linux/macOS notifyChange safety +- [x] Smoke script covering persisted keys across processes diff --git a/specs/aps-cli/testing.md b/specs/aps-cli/testing.md new file mode 100644 index 0000000..5632227 --- /dev/null +++ b/specs/aps-cli/testing.md @@ -0,0 +1,5 @@ +# Testing - APS CLI + +- Unit: DemoKey metadata, parseBool, invalid set values +- Integration: StateStore round-trips via `@testable import aps` +- Smoke: `Scripts/smoke.sh` for flag/note persistence and reset diff --git a/specs/state-store/context.md b/specs/state-store/context.md new file mode 100644 index 0000000..9d6b438 --- /dev/null +++ b/specs/state-store/context.md @@ -0,0 +1,3 @@ +# Context - State Store + +StateStore is the non-UI AppState facade used by the CLI. It owns persistence quirks (Linux UserDefaults flush) and Observation-based watching. diff --git a/specs/state-store/requirements.md b/specs/state-store/requirements.md new file mode 100644 index 0000000..a56d128 --- /dev/null +++ b/specs/state-store/requirements.md @@ -0,0 +1,41 @@ +--- +spec: state-store.spec.md +--- + +# Requirements - State Store + +## Functional + +### REQ-state-store-001 + +`StateStore` SHALL read and write demo keys through AppState Application extensions on the main actor via `init`, `get`, and `set`. + +Acceptance Criteria +- `get`/`set` round-trip `counter`, `message`, `flag`, and `note`. +- Mutating paths are MainActor-isolated. + +### REQ-state-store-002 + +`StateStore` SHALL inject real `APSClock` / `SystemAPSClock` (`now`) and `JSONCoding` (`encodePretty`, `decode`) dependencies for `dump` output. + +Acceptance Criteria +- `dump` JSON includes every `DemoKey` and a timestamp. +- Dependencies are loaded via `Application.dependency` / `@AppDependency`. + +### REQ-state-store-003 + +Writing `flag` SHALL flush UserDefaults so Linux short-lived processes persist StoredState; `reset` / `resetAll` restore initials. + +Acceptance Criteria +- After `set(.flag, "true")`, a new `StateStore` instance observes true. +- `reset(.flag)` restores false and flushes. + +### REQ-state-store-004 + +`watchBlocking` SHALL combine Observation with RunLoop polling and honor `shouldContinue`; `parseBool` accepts common truthy/falsey tokens. + +Acceptance Criteria +- In-process `State` mutations are observed. +- `FileState` mutations performed during the loop are observed. +- `shouldContinue` false stops the loop without requiring Ctrl-C. + diff --git a/specs/state-store/state-store.spec.md b/specs/state-store/state-store.spec.md index f24d7b4..03b3d7c 100644 --- a/specs/state-store/state-store.spec.md +++ b/specs/state-store/state-store.spec.md @@ -1,7 +1,7 @@ --- module: state-store -version: 1 -status: draft +version: 3 +status: active files: - Sources/aps/StateStore.swift - Sources/aps/DemoState.swift @@ -21,34 +21,25 @@ non-UI use. ## Public API -### Application demo surface (`DemoState.swift`) - -| Member | Kind | Initial | -|--------|------|---------| -| `Application.counter` | `State` | `0` | -| `Application.message` | `State` | `""` | -| `Application.flag` | `StoredState` | `false` | -| `Application.note` | `FileState` | `""` | -| `Application.clock` | `Dependency` | `SystemAPSClock()` | -| `Application.jsonCoding` | `Dependency` | `JSONCoding()` | - -`APSPaths.configure()` points `FileManager.defaultFileStatePath` at `~/.aps`. - -### StateStore - -| Method | Role | -|--------|------| -| `get(_:)` | Return the string form of a demo key. | -| `set(_:value:)` | Parse and write; throw `APSError.invalidValue` on bad input. | -| `reset(_:)` / `resetAll()` | Restore AppState initials (and flush UserDefaults for `flag`). | -| `dump()` | Pretty JSON snapshot using `@AppDependency` clock + jsonCoding. | -| `watchBlocking(_:pollInterval:shouldContinue:onChange:)` | Observation + RunLoop poll loop. | -| `parseBool(_:)` | Accept true/false/1/0/yes/no/on/off (case-insensitive). | - -### Dependencies (`Dependencies.swift`) - -- `APSClock` / `SystemAPSClock`: wall-clock for dump timestamps -- `JSONCoding`: shared pretty JSON encode/decode helpers +| Export | Description | +|--------|-------------| +| `StateStore` | MainActor AppState facade used by the CLI. | +| `APSClock` | Clock protocol for dump timestamps. | +| `SystemAPSClock` | Production `APSClock` backed by `Date()`. | +| `JSONCoding` | Shared pretty JSON helpers. | +| `init` | Configures FileState path and loads clock/jsonCoding dependencies. | +| `get` | Return the string form of a demo key. | +| `set` | Parse and write; throw `APSError.invalidValue` on bad input. | +| `reset` | Restore one key to its AppState initial value. | +| `resetAll` | Restore every demo key. | +| `dump` | Pretty JSON snapshot using `@AppDependency` clock + jsonCoding. | +| `watchBlocking` | Observation + RunLoop poll loop with `shouldContinue`. | +| `parseBool` | Accept true/false/1/0/yes/no/on/off (case-insensitive). | +| `now` | Current `Date` from an `APSClock`. | +| `encodePretty` | Encode an `Encodable` value as pretty UTF-8 JSON text. | +| `decode` | Decode a `Decodable` value from UTF-8 JSON text. | + +Application demo surface (informational): `Application.counter` / `message` / `flag` / `note` / `clock` / `jsonCoding`, with `APSPaths.configure()` pointing FileState at `~/.aps`. ## Invariants @@ -101,3 +92,5 @@ Then keys include message with value "hi" and a timestamp field exists. ## Change Log - 1: Initial StateStore / Application demo-state contract for the aps CLI. +- 2: Explicit export inventory for SpecSync active-contract checks. +| 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | diff --git a/specs/state-store/tasks.md b/specs/state-store/tasks.md new file mode 100644 index 0000000..df8f8c7 --- /dev/null +++ b/specs/state-store/tasks.md @@ -0,0 +1,6 @@ +# Tasks - State Store + +- [x] Application demo keys: State, StoredState, FileState +- [x] APSClock and JSONCoding dependencies +- [x] dump / reset / watchBlocking helpers +- [x] UserDefaults.synchronize after flag writes diff --git a/specs/state-store/testing.md b/specs/state-store/testing.md new file mode 100644 index 0000000..f1a1ec5 --- /dev/null +++ b/specs/state-store/testing.md @@ -0,0 +1,6 @@ +# Testing - State Store + +- Round-trip tests for each DemoKey +- reset and resetAll restore initials +- watchBlocking in-process and FileState change detection +- dump includes dependency-driven timestamp and all keys From fbcb4636cc4a05c7c21da5342042ec9d541d90db Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 18 Jul 2026 16:50:16 +0000 Subject: [PATCH 5/9] Refresh SpecSync acceptance evidence after companion finalization Reopen and re-accept CHG-0001 so closing evidence matches the delivered companion files and stays exact for Trust/specsync checks. Co-authored-by: Leif --- .../approvals.json | 416 +++++++++++++++++- .../state.json | 2 +- .../verification-attempts.json | 25 ++ .../verification.json | 40 +- 4 files changed, 461 insertions(+), 22 deletions(-) diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json index efa4698..d26d9e1 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json @@ -41,7 +41,421 @@ "timestamp": 1784393368, "digest": "6d19a3078f062938ee3e14692d1ed6694ceb70bdc794146a86108cc8c1de509b", "note": "Accept after local verify green; CI awaits macOS self-hosted runners." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784393403, + "digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "note": "Re-approve after reopen for companion finalization." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784393407, + "digest": "4145e1bdd5239a9d33b52c4208171b5d98be0b5ecc5e1d1e28451194cb689de8", + "note": "Re-accept with current companions and export tables." } ], - "reopenings": [] + "reopenings": [ + { + "schema_version": 1, + "change_id": "CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts", + "actor": "leif algo", + "reason": "Companion context/testing/tasks files were finalized after first accept, making accepted delivery evidence stale.", + "timestamp": 1784393403, + "from_state": "accepted", + "to_state": "verifying", + "superseded_approval": { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784393368, + "digest": "6d19a3078f062938ee3e14692d1ed6694ceb70bdc794146a86108cc8c1de509b", + "note": "Accept after local verify green; CI awaits macOS self-hosted runners." + }, + "prior_verification": { + "timestamp": 1784393368, + "commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", + "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "workspace_digest": "c8511495beb59a1886f889207c2367c0cad3fa3efcba98a29d28ef1a1c5ddcd0", + "acceptance_input_digest": "e410fc1465ce16aa200e9d509f4455dc3cea215a8640e82d20608be2d58745c2", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": ".attest.json", + "kind": "file", + "mode": 33188, + "payload_digest": "fda17571040ce10c378e009859f92cc33afd67b5c62d3f96510bf9e6e5de0a9f", + "entry_digest": "9d185be1f08f917f1162191bbd90ca325f047bec1cda66f2fc6d0737c08da1ab", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".augur.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "17f6ad5b84b4db012f0e3f398a96a478c1324fd47e72e1dd2a13c7cf9a432983", + "entry_digest": "bac13c952da05292bdd0af5849aad9d9def3ae5afc830fa42b6914b2fd874beb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/ci.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "1f310d5d11b4466aedf85aac75d7db13b07d564f1e38e2f596defb8cf2f06d1c", + "entry_digest": "9abaefb404d6bb884367be7ea7524e890c9bab326c810c0985569c35a83418e7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/trust.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "f4fad2f8914de3e6285b1afce3dc3ebe624e657aecc3bb2312fd6c3003a76f7f", + "entry_digest": "a1f5ca04418295d7d3919880416b2166a40ca6b0ac527a83458ecf51d26d2788", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "30d23b531c3fcb3e46c413c3d06d3c2848bb273aaf86abdee660e201ed9519a9", + "entry_digest": "8c2aa3eee1fa32d85bddb1f5daf626a0a97ce920f434cd2ec57050fe1623867a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/.gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "a3129d6f93250ade8dbacfc73bc7eeae0cc47c2f7032142ca47cb4f1ffb2483e", + "entry_digest": "9badbf40b83d05f58bafda0fc2cafccfe726e4da7e6e67ef513e822989e13f04", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/change-sequence.json", + "kind": "file", + "mode": 33188, + "payload_digest": "1f95d9c5ccca97dabb0fa17a4d2b2491023b263fb475e5a03e784eeb63f7232a", + "entry_digest": "f4b667fec7bde996c7c0f9b31f7ea84ddef37f171371f3e0084c0bb9a66978af", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/config.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "54a83f6a4a252649bac390d2e936aa0815711fba86b6bfc8ea8fff2fffdfd29b", + "entry_digest": "e60f979233a7db75ce63f4ef42d6f1f7676ad1655a438b9baf78558aba60ec3e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/registry.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "c423be1a5cf87318f85dc252fe0acd1c1486c5224ddc2d8e19bea1ac9c69c820", + "entry_digest": "7e1f068900ced849b8d1028ca40165fbdc5280ae7f53452f0e57e2710d895848", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/sdd.json", + "kind": "file", + "mode": 33188, + "payload_digest": "2d5fb3058b1ee4ce584c3cda9410c193c4893e272ed459205e58bfde06afc7b0", + "entry_digest": "8c6b11fc5787eb04e7ee651eb15fbf98fc3ea22db37e65423e3d75f99c09df19", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/version", + "kind": "file", + "mode": 33188, + "payload_digest": "23b6867924dfeb9cf532753438dc919669bf93ad88215e11c15630a4acbf4299", + "entry_digest": "339b5f88be30302336707baa5dab61fd4b324d04e495d3bb772cf893fb4f73bc", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".trust.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "6284ced27613c8e2dd8266ffd1668f021cb24e1edb6ccd79c9ade86032c09ce8", + "entry_digest": "7cdd9144620ced58d9ac48ee7d2b8563f5564f1ae2db02a22e7eed781963257e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "AGENTS.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a671dd50eea50f115e6f9abd554e5a8ad7e520208fec5c4bd540c4f3a07ef807", + "entry_digest": "c321960d8ebbf18c2833c8f8b7fe413d6f0e349b424bf2b296a4da7a26316750", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "CLAUDE.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e2df5028858a540821e4a666297d536a14bf598d48afe6c44df921b0f1ddbf32", + "entry_digest": "6930540d6a42ffd8c849bdf10eaf69c3f231cf5e824c9e6f0e694d3edb91bda3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.resolved", + "kind": "file", + "mode": 33188, + "payload_digest": "12eea9fa129e151eaffdc230a234293407f0e3a99c52f15597c72e4e591c0e1e", + "entry_digest": "554d48ebe132641edab54e1d89d163cc2534521a9f41750ed5bd8582723a2d28", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", + "entry_digest": "0b185dd498f42e05a6cc8c2447d547432f4c40000c5dc26f17fe0fc7ae21d6cb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "247d8f2d3f67cf9a7c3641ad26bc37a016fa4c7a637f8d0349864f85de6e6bad", + "entry_digest": "464275632b4b92467210ce1683caa823bd308fcc98cedf860e53da9e37d563a6", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Scripts/smoke.sh", + "kind": "file", + "mode": 33261, + "payload_digest": "5947d02b95d6205d63beca54876398d81226d0d4796b4234b646a3b919f08b4c", + "entry_digest": "a847aedf94fa22e35460140f14bdd4be567c550ddc2d20ade0f672329f3efbd7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Sources/aps/Aps.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "17c9cb972eec5b29d19adf9ea64e125ef03d8bbfb8f5115e438a309c0a1d4316", + "entry_digest": "19304c7bb4daa894ed568d6ead0153390bc7011acf03d1d08addf0b3ac13e4a4", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoKey.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f973ce1f86e31efd412a76938db78bbd36b01b6ee7dbb48a9865edb569917380", + "entry_digest": "5d391ca2c3462528b91a83888a6b09484f850995b504d01f61a31c91ec3a80db", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoState.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "036eed2ac58afdf87b30938911658abe74888fd3ca2c6a63869de3f5f2701125", + "entry_digest": "7dda9ef80f141fffd93dc5a6dfa9c41b5f2c7ce28265341e764b72269c687595", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/Dependencies.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "635340259dcd618bf5099e07dad823f72f4517f6a2762ec1e6b67965221ccef2", + "entry_digest": "637ab3fca33111ebb5f145cdd632e7a6412e99d88d08e3890ab1cc3edc54c736", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/StateStore.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "d6773947e8268bac77da4c323b541ef5fe514939d4ef0cafd74ecbd3a4a3ece3", + "entry_digest": "190b8e0e4aa74797e09b64e1576b3ddb5b57dcf991cd71a5951fe3e606803c08", + "owners": [ + "state-store" + ] + }, + { + "path": "Tests/apsTests/APSTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "55ac9e3657a48995bad11dfe75de46f9e367b3cf0a0250b90d685392d4e09a15", + "entry_digest": "388f64f61823bb9f78051c74227da3839f15955a8bae50b579003c5bc13fe78e", + "owners": [ + "@exact:test" + ] + }, + { + "path": "fledge.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "f69feb965265eb9481197160885409a03d0eb367149a2955c7b17a98dee9ba4e", + "entry_digest": "4994cce91eb6ed15dcf039ff4ce7194b901fe8e5ef33905503817173f42b6560", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/aps-cli/aps-cli.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "f5cc6d9e1f1f328b100b826707470577669dc24e46cc4f8f9d98164a2f0339a8", + "entry_digest": "07206127871185e01418a2f11a620743fcb70666abdcbcc895a8d0f8a88fd536", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "57d3395961e0cbe4ca7c02b638cd0e5da34214f3fd0c1342914eec6cccd3ff8c", + "entry_digest": "ccba3dc943b3128bef61641fe7c5b57c14393ad0e009353b6f86cd0446890fbf", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "6f0a119928aaded71476b059b3950aea3dfcc80d32a377857ed4b0ad5b1240a1", + "entry_digest": "fb8e378328b81db7a39be58a5e31c8627a99a63f834e92bc65062718c7caa69a", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "d4310391e8703dbcf632a37901ed8c65d0675e5830284325269e7fe371b6094f", + "entry_digest": "5e3171593d0abe547a27788401056cfce4f911383ef4526cc3f3bdc3150361e8", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "d1b40f1198fb2b23d3452450afb5c84748d95c38efd81529213cb75cdc5071c9", + "entry_digest": "dab7bdb784204ee22cad510b0de8008ea539ca747419f3c818003deae04cbbd3", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/state-store/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "35090a0e0d4e0b10ac64cccd5f6346b7380ff6a5d6180ec732f12eb554c00bf7", + "entry_digest": "3df91075712a9b76bb0d810a76ab3bcb75f2518680c69356c843a166a2934691", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "1e877f271ce3b3794a5019b4321b6bf971ddf08bdf400a2e5405587c35a8f606", + "entry_digest": "92c4d1f84ee0874655e25e66422faa80470e7e0512e51124755fb6ed36ea6ef8", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/state-store.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "1531480af30af3a268a1234b78346bced142443d04cd1e67b1488a2541404084", + "entry_digest": "875548708b0830fbce9aa616293cdacf7e89f2ac23d391aa85057fa8cf5ab24d", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "4a931c764c1b83ba70ead17a33f55aaf4356a367f600f10724b963b9d1c6ca92", + "entry_digest": "bd414350cad0fccf90e0acd9da163a4e7d4242a653bd9d6b475cd58530858666", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "159bf0c984c3490f5f7da8704b9153f41f8bc2ced3ea43246123a72d5a3f7783", + "entry_digest": "dd51d33d0d6928c2f90459f02abe826ee4a95490baefcf4ace149a9fb2f47c91", + "owners": [ + "state-store" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-001", + "REQ-aps-cli-002", + "REQ-aps-cli-003", + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-002", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + "stale_acceptance_input_digest": "e410fc1465ce16aa200e9d509f4455dc3cea215a8640e82d20608be2d58745c2", + "current_acceptance_input_digest": "c712cc9484f9f9320b8147848156a7969e812368f28597a265f68965c0c48057" + } + ] } diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json index 69bed72..c8f39d1 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json @@ -9,7 +9,7 @@ "canonical_applied": true, "base_commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", "created_at": 1784393134, - "updated_at": 1784393368, + "updated_at": 1784393407, "affected_specs": [ "aps-cli", "state-store" diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json index f818685..33f5aa5 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json @@ -50,6 +50,31 @@ "REQ-state-store-003", "REQ-state-store-004" ] + }, + { + "timestamp": 1784393406, + "commit": "d5f28efeb86135279b7a5ba8bed8894a2c290a35", + "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "workspace_digest": "617795e00f0d67a61a7059e8e4cd218dc16e0dd45f517e3bedbf55c83312d7fa", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-001", + "REQ-aps-cli-002", + "REQ-aps-cli-003", + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-002", + "REQ-state-store-003", + "REQ-state-store-004" + ] } ] } diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json index 8682e3b..512344d 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json @@ -1,9 +1,9 @@ { - "timestamp": 1784393368, - "commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", + "timestamp": 1784393406, + "commit": "d5f28efeb86135279b7a5ba8bed8894a2c290a35", "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "workspace_digest": "c8511495beb59a1886f889207c2367c0cad3fa3efcba98a29d28ef1a1c5ddcd0", - "acceptance_input_digest": "e410fc1465ce16aa200e9d509f4455dc3cea215a8640e82d20608be2d58745c2", + "workspace_digest": "617795e00f0d67a61a7059e8e4cd218dc16e0dd45f517e3bedbf55c83312d7fa", + "acceptance_input_digest": "c712cc9484f9f9320b8147848156a7969e812368f28597a265f68965c0c48057", "acceptance_manifest": { "schema_version": 1, "entries": [ @@ -271,8 +271,8 @@ "path": "specs/aps-cli/context.md", "kind": "file", "mode": 33188, - "payload_digest": "57d3395961e0cbe4ca7c02b638cd0e5da34214f3fd0c1342914eec6cccd3ff8c", - "entry_digest": "ccba3dc943b3128bef61641fe7c5b57c14393ad0e009353b6f86cd0446890fbf", + "payload_digest": "6a67354ec782d88510bea4b0ec28e1b1a3c50fc01e625ee32d6783f4dfbc86e0", + "entry_digest": "9cb95bb0d687799ba10637230b404cbef8a5abfb45d46a07a7bb50bee9703431", "owners": [ "aps-cli" ] @@ -281,8 +281,8 @@ "path": "specs/aps-cli/requirements.md", "kind": "file", "mode": 33188, - "payload_digest": "6f0a119928aaded71476b059b3950aea3dfcc80d32a377857ed4b0ad5b1240a1", - "entry_digest": "fb8e378328b81db7a39be58a5e31c8627a99a63f834e92bc65062718c7caa69a", + "payload_digest": "683b7544c36c0a73b5a62ebdad6888f68488e0f3a31aed479f3cc5b81635c0ad", + "entry_digest": "9173ab3068d73f055b46c7b896e6de1241582da3162e2365ba59367a28fce056", "owners": [ "aps-cli" ] @@ -291,8 +291,8 @@ "path": "specs/aps-cli/tasks.md", "kind": "file", "mode": 33188, - "payload_digest": "d4310391e8703dbcf632a37901ed8c65d0675e5830284325269e7fe371b6094f", - "entry_digest": "5e3171593d0abe547a27788401056cfce4f911383ef4526cc3f3bdc3150361e8", + "payload_digest": "b6f0c8e3aa90f43e5dc40389e77088b2ec6ebb725c89c57217970fc1c221f527", + "entry_digest": "af31087c96d633274df81aecd4e99f520a55995882545190d2d42bb30fa5c3aa", "owners": [ "aps-cli" ] @@ -301,8 +301,8 @@ "path": "specs/aps-cli/testing.md", "kind": "file", "mode": 33188, - "payload_digest": "d1b40f1198fb2b23d3452450afb5c84748d95c38efd81529213cb75cdc5071c9", - "entry_digest": "dab7bdb784204ee22cad510b0de8008ea539ca747419f3c818003deae04cbbd3", + "payload_digest": "14420af80f34d7954894aaf63f9864db13eea74549796043f54badf82805394a", + "entry_digest": "1227fad23fad49d312453dfe8fffc2bfe67396fdb29c88dab355bd60e8ec91b5", "owners": [ "aps-cli" ] @@ -311,8 +311,8 @@ "path": "specs/state-store/context.md", "kind": "file", "mode": 33188, - "payload_digest": "35090a0e0d4e0b10ac64cccd5f6346b7380ff6a5d6180ec732f12eb554c00bf7", - "entry_digest": "3df91075712a9b76bb0d810a76ab3bcb75f2518680c69356c843a166a2934691", + "payload_digest": "ddb4564d168db43eadd6315a7f56b532198905a79abebfee77db890db0f9c402", + "entry_digest": "a14edf94507dfd13d7d325bf68e370e0c1646e323b28341bd0c1dfff72f05d88", "owners": [ "state-store" ] @@ -321,8 +321,8 @@ "path": "specs/state-store/requirements.md", "kind": "file", "mode": 33188, - "payload_digest": "1e877f271ce3b3794a5019b4321b6bf971ddf08bdf400a2e5405587c35a8f606", - "entry_digest": "92c4d1f84ee0874655e25e66422faa80470e7e0512e51124755fb6ed36ea6ef8", + "payload_digest": "713553c4b9f57ec521c060f1e191963f15c8c6a82a55e33ed0730538b6b2ee8d", + "entry_digest": "aa26dc21220beeea694456c16a04ed4fe9cf7db95c3d52ae911b8f18dc02e049", "owners": [ "state-store" ] @@ -341,8 +341,8 @@ "path": "specs/state-store/tasks.md", "kind": "file", "mode": 33188, - "payload_digest": "4a931c764c1b83ba70ead17a33f55aaf4356a367f600f10724b963b9d1c6ca92", - "entry_digest": "bd414350cad0fccf90e0acd9da163a4e7d4242a653bd9d6b475cd58530858666", + "payload_digest": "711db2a24a4959531ca966ac43d96e7817788ebe74077280a6cff950cb9a8779", + "entry_digest": "8402318068cd8ab6f8a596519289e70425dbc28bf6b31d5c1ef6f0a17f927f74", "owners": [ "state-store" ] @@ -351,8 +351,8 @@ "path": "specs/state-store/testing.md", "kind": "file", "mode": 33188, - "payload_digest": "159bf0c984c3490f5f7da8704b9153f41f8bc2ced3ea43246123a72d5a3f7783", - "entry_digest": "dd51d33d0d6928c2f90459f02abe826ee4a95490baefcf4ace149a9fb2f47c91", + "payload_digest": "96fbc44cdbe25dfab52a47f8efdbd4698203571981b181c78a04769112402f1d", + "entry_digest": "8b0abd2a0f6613b9caa1f2831cdf8776b80a1945552eade241ff3d3b8d6404af", "owners": [ "state-store" ] From ae4cf265007ab3b0a1f608fb39842f4c3d88643c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 18 Jul 2026 17:11:59 +0000 Subject: [PATCH 6/9] Fix Trust CI range for tokenized self-hosted checkouts Pass an explicit base..head comparison range so CorvidLabs Trust does not treat the credentialed origin remote as an external repository. Co-authored-by: Leif --- .github/workflows/trust.yml | 18 + .../approvals.json | 420 ++++++++++++++++++ .../state.json | 2 +- .../verification-attempts.json | 50 +++ .../verification.json | 12 +- 5 files changed, 495 insertions(+), 7 deletions(-) diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml index b3cddbf..9f9a75c 100644 --- a/.github/workflows/trust.yml +++ b/.github/workflows/trust.yml @@ -24,9 +24,27 @@ jobs: - name: Fetch attest notes run: git fetch origin "+refs/notes/attest:refs/notes/attest" 2>/dev/null || true + # actions/checkout embeds a token in origin; Trust then treats the worktree + # as external and refuses event-derived ranges. Pass the canonical range + # explicitly while keeping credentials for private-repo note fetches. + - name: Resolve Trust comparison range + id: trust_range + run: | + set -euo pipefail + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "range=${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}" >> "$GITHUB_OUTPUT" + elif [ -z "${{ github.event.before }}" ] || [ "${{ github.event.before }}" = "0000000000000000000000000000000000000000" ]; then + empty="$(git hash-object -t tree /dev/null)" + echo "range=${empty}..${{ github.sha }}" >> "$GITHUB_OUTPUT" + else + echo "range=${{ github.event.before }}..${{ github.sha }}" >> "$GITHUB_OUTPUT" + fi + - name: CorvidLabs Trust gate id: trust uses: CorvidLabs/trust@9d32b5786d2e9e4d39fc581c0091c721ee3d4226 # v1.0.0 + with: + range: ${{ steps.trust_range.outputs.range }} - name: Check managed agent rules run: | diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json index d26d9e1..f356cf5 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json @@ -55,6 +55,27 @@ "timestamp": 1784393407, "digest": "4145e1bdd5239a9d33b52c4208171b5d98be0b5ecc5e1d1e28451194cb689de8", "note": "Re-accept with current companions and export tables." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784394701, + "digest": "cc9272eb0555774991e025749c04256dc796539787c1ae0b118f5f94c008163e", + "note": "Approve Trust workflow range fix for self-hosted CI." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784394711, + "digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "note": "Re-approve unchanged definition after Trust workflow delivery fix." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784394715, + "digest": "bf47283138ee6da7f4434e6ff1ca9b7d34db666ea784474b36b45eec525f2ccc", + "note": "Re-accept with Trust range workflow delivery fix." } ], "reopenings": [ @@ -456,6 +477,405 @@ }, "stale_acceptance_input_digest": "e410fc1465ce16aa200e9d509f4455dc3cea215a8640e82d20608be2d58745c2", "current_acceptance_input_digest": "c712cc9484f9f9320b8147848156a7969e812368f28597a265f68965c0c48057" + }, + { + "schema_version": 1, + "change_id": "CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts", + "actor": "leif algo", + "reason": "Trust workflow needs an explicit comparison range because tokenized checkout remotes are treated as external.", + "timestamp": 1784394701, + "from_state": "accepted", + "to_state": "verifying", + "superseded_approval": { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784393407, + "digest": "4145e1bdd5239a9d33b52c4208171b5d98be0b5ecc5e1d1e28451194cb689de8", + "note": "Re-accept with current companions and export tables." + }, + "prior_verification": { + "timestamp": 1784393406, + "commit": "d5f28efeb86135279b7a5ba8bed8894a2c290a35", + "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "workspace_digest": "617795e00f0d67a61a7059e8e4cd218dc16e0dd45f517e3bedbf55c83312d7fa", + "acceptance_input_digest": "c712cc9484f9f9320b8147848156a7969e812368f28597a265f68965c0c48057", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": ".attest.json", + "kind": "file", + "mode": 33188, + "payload_digest": "fda17571040ce10c378e009859f92cc33afd67b5c62d3f96510bf9e6e5de0a9f", + "entry_digest": "9d185be1f08f917f1162191bbd90ca325f047bec1cda66f2fc6d0737c08da1ab", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".augur.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "17f6ad5b84b4db012f0e3f398a96a478c1324fd47e72e1dd2a13c7cf9a432983", + "entry_digest": "bac13c952da05292bdd0af5849aad9d9def3ae5afc830fa42b6914b2fd874beb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/ci.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "1f310d5d11b4466aedf85aac75d7db13b07d564f1e38e2f596defb8cf2f06d1c", + "entry_digest": "9abaefb404d6bb884367be7ea7524e890c9bab326c810c0985569c35a83418e7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/trust.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "f4fad2f8914de3e6285b1afce3dc3ebe624e657aecc3bb2312fd6c3003a76f7f", + "entry_digest": "a1f5ca04418295d7d3919880416b2166a40ca6b0ac527a83458ecf51d26d2788", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "30d23b531c3fcb3e46c413c3d06d3c2848bb273aaf86abdee660e201ed9519a9", + "entry_digest": "8c2aa3eee1fa32d85bddb1f5daf626a0a97ce920f434cd2ec57050fe1623867a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/.gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "a3129d6f93250ade8dbacfc73bc7eeae0cc47c2f7032142ca47cb4f1ffb2483e", + "entry_digest": "9badbf40b83d05f58bafda0fc2cafccfe726e4da7e6e67ef513e822989e13f04", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/change-sequence.json", + "kind": "file", + "mode": 33188, + "payload_digest": "1f95d9c5ccca97dabb0fa17a4d2b2491023b263fb475e5a03e784eeb63f7232a", + "entry_digest": "f4b667fec7bde996c7c0f9b31f7ea84ddef37f171371f3e0084c0bb9a66978af", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/config.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "54a83f6a4a252649bac390d2e936aa0815711fba86b6bfc8ea8fff2fffdfd29b", + "entry_digest": "e60f979233a7db75ce63f4ef42d6f1f7676ad1655a438b9baf78558aba60ec3e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/registry.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "c423be1a5cf87318f85dc252fe0acd1c1486c5224ddc2d8e19bea1ac9c69c820", + "entry_digest": "7e1f068900ced849b8d1028ca40165fbdc5280ae7f53452f0e57e2710d895848", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/sdd.json", + "kind": "file", + "mode": 33188, + "payload_digest": "2d5fb3058b1ee4ce584c3cda9410c193c4893e272ed459205e58bfde06afc7b0", + "entry_digest": "8c6b11fc5787eb04e7ee651eb15fbf98fc3ea22db37e65423e3d75f99c09df19", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/version", + "kind": "file", + "mode": 33188, + "payload_digest": "23b6867924dfeb9cf532753438dc919669bf93ad88215e11c15630a4acbf4299", + "entry_digest": "339b5f88be30302336707baa5dab61fd4b324d04e495d3bb772cf893fb4f73bc", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".trust.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "6284ced27613c8e2dd8266ffd1668f021cb24e1edb6ccd79c9ade86032c09ce8", + "entry_digest": "7cdd9144620ced58d9ac48ee7d2b8563f5564f1ae2db02a22e7eed781963257e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "AGENTS.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a671dd50eea50f115e6f9abd554e5a8ad7e520208fec5c4bd540c4f3a07ef807", + "entry_digest": "c321960d8ebbf18c2833c8f8b7fe413d6f0e349b424bf2b296a4da7a26316750", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "CLAUDE.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e2df5028858a540821e4a666297d536a14bf598d48afe6c44df921b0f1ddbf32", + "entry_digest": "6930540d6a42ffd8c849bdf10eaf69c3f231cf5e824c9e6f0e694d3edb91bda3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.resolved", + "kind": "file", + "mode": 33188, + "payload_digest": "12eea9fa129e151eaffdc230a234293407f0e3a99c52f15597c72e4e591c0e1e", + "entry_digest": "554d48ebe132641edab54e1d89d163cc2534521a9f41750ed5bd8582723a2d28", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", + "entry_digest": "0b185dd498f42e05a6cc8c2447d547432f4c40000c5dc26f17fe0fc7ae21d6cb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "247d8f2d3f67cf9a7c3641ad26bc37a016fa4c7a637f8d0349864f85de6e6bad", + "entry_digest": "464275632b4b92467210ce1683caa823bd308fcc98cedf860e53da9e37d563a6", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Scripts/smoke.sh", + "kind": "file", + "mode": 33261, + "payload_digest": "5947d02b95d6205d63beca54876398d81226d0d4796b4234b646a3b919f08b4c", + "entry_digest": "a847aedf94fa22e35460140f14bdd4be567c550ddc2d20ade0f672329f3efbd7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Sources/aps/Aps.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "17c9cb972eec5b29d19adf9ea64e125ef03d8bbfb8f5115e438a309c0a1d4316", + "entry_digest": "19304c7bb4daa894ed568d6ead0153390bc7011acf03d1d08addf0b3ac13e4a4", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoKey.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f973ce1f86e31efd412a76938db78bbd36b01b6ee7dbb48a9865edb569917380", + "entry_digest": "5d391ca2c3462528b91a83888a6b09484f850995b504d01f61a31c91ec3a80db", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoState.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "036eed2ac58afdf87b30938911658abe74888fd3ca2c6a63869de3f5f2701125", + "entry_digest": "7dda9ef80f141fffd93dc5a6dfa9c41b5f2c7ce28265341e764b72269c687595", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/Dependencies.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "635340259dcd618bf5099e07dad823f72f4517f6a2762ec1e6b67965221ccef2", + "entry_digest": "637ab3fca33111ebb5f145cdd632e7a6412e99d88d08e3890ab1cc3edc54c736", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/StateStore.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "d6773947e8268bac77da4c323b541ef5fe514939d4ef0cafd74ecbd3a4a3ece3", + "entry_digest": "190b8e0e4aa74797e09b64e1576b3ddb5b57dcf991cd71a5951fe3e606803c08", + "owners": [ + "state-store" + ] + }, + { + "path": "Tests/apsTests/APSTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "55ac9e3657a48995bad11dfe75de46f9e367b3cf0a0250b90d685392d4e09a15", + "entry_digest": "388f64f61823bb9f78051c74227da3839f15955a8bae50b579003c5bc13fe78e", + "owners": [ + "@exact:test" + ] + }, + { + "path": "fledge.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "f69feb965265eb9481197160885409a03d0eb367149a2955c7b17a98dee9ba4e", + "entry_digest": "4994cce91eb6ed15dcf039ff4ce7194b901fe8e5ef33905503817173f42b6560", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/aps-cli/aps-cli.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "f5cc6d9e1f1f328b100b826707470577669dc24e46cc4f8f9d98164a2f0339a8", + "entry_digest": "07206127871185e01418a2f11a620743fcb70666abdcbcc895a8d0f8a88fd536", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "6a67354ec782d88510bea4b0ec28e1b1a3c50fc01e625ee32d6783f4dfbc86e0", + "entry_digest": "9cb95bb0d687799ba10637230b404cbef8a5abfb45d46a07a7bb50bee9703431", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "683b7544c36c0a73b5a62ebdad6888f68488e0f3a31aed479f3cc5b81635c0ad", + "entry_digest": "9173ab3068d73f055b46c7b896e6de1241582da3162e2365ba59367a28fce056", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "b6f0c8e3aa90f43e5dc40389e77088b2ec6ebb725c89c57217970fc1c221f527", + "entry_digest": "af31087c96d633274df81aecd4e99f520a55995882545190d2d42bb30fa5c3aa", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "14420af80f34d7954894aaf63f9864db13eea74549796043f54badf82805394a", + "entry_digest": "1227fad23fad49d312453dfe8fffc2bfe67396fdb29c88dab355bd60e8ec91b5", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/state-store/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "ddb4564d168db43eadd6315a7f56b532198905a79abebfee77db890db0f9c402", + "entry_digest": "a14edf94507dfd13d7d325bf68e370e0c1646e323b28341bd0c1dfff72f05d88", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "713553c4b9f57ec521c060f1e191963f15c8c6a82a55e33ed0730538b6b2ee8d", + "entry_digest": "aa26dc21220beeea694456c16a04ed4fe9cf7db95c3d52ae911b8f18dc02e049", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/state-store.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "1531480af30af3a268a1234b78346bced142443d04cd1e67b1488a2541404084", + "entry_digest": "875548708b0830fbce9aa616293cdacf7e89f2ac23d391aa85057fa8cf5ab24d", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "711db2a24a4959531ca966ac43d96e7817788ebe74077280a6cff950cb9a8779", + "entry_digest": "8402318068cd8ab6f8a596519289e70425dbc28bf6b31d5c1ef6f0a17f927f74", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "96fbc44cdbe25dfab52a47f8efdbd4698203571981b181c78a04769112402f1d", + "entry_digest": "8b0abd2a0f6613b9caa1f2831cdf8776b80a1945552eade241ff3d3b8d6404af", + "owners": [ + "state-store" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-001", + "REQ-aps-cli-002", + "REQ-aps-cli-003", + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-002", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + "stale_acceptance_input_digest": "c712cc9484f9f9320b8147848156a7969e812368f28597a265f68965c0c48057", + "current_acceptance_input_digest": "99d27392ebbf304fa0b23e510a3a7f26f1c54cd9068221cc5b0f938a7bbc4c52" } ] } diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json index c8f39d1..5b061d4 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json @@ -9,7 +9,7 @@ "canonical_applied": true, "base_commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", "created_at": 1784393134, - "updated_at": 1784393407, + "updated_at": 1784394715, "affected_specs": [ "aps-cli", "state-store" diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json index 33f5aa5..b5b2f1f 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json @@ -75,6 +75,56 @@ "REQ-state-store-003", "REQ-state-store-004" ] + }, + { + "timestamp": 1784394704, + "commit": "fbcb4636cc4a05c7c21da5342042ec9d541d90db", + "contract_digest": "cc9272eb0555774991e025749c04256dc796539787c1ae0b118f5f94c008163e", + "workspace_digest": "d89692495b79a09750d340fdf0f552ef89651a3e7b75a409d9adf4890456cef2", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-001", + "REQ-aps-cli-002", + "REQ-aps-cli-003", + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-002", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + { + "timestamp": 1784394714, + "commit": "fbcb4636cc4a05c7c21da5342042ec9d541d90db", + "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "workspace_digest": "d89692495b79a09750d340fdf0f552ef89651a3e7b75a409d9adf4890456cef2", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-001", + "REQ-aps-cli-002", + "REQ-aps-cli-003", + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-002", + "REQ-state-store-003", + "REQ-state-store-004" + ] } ] } diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json index 512344d..947c237 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json @@ -1,9 +1,9 @@ { - "timestamp": 1784393406, - "commit": "d5f28efeb86135279b7a5ba8bed8894a2c290a35", + "timestamp": 1784394714, + "commit": "fbcb4636cc4a05c7c21da5342042ec9d541d90db", "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "workspace_digest": "617795e00f0d67a61a7059e8e4cd218dc16e0dd45f517e3bedbf55c83312d7fa", - "acceptance_input_digest": "c712cc9484f9f9320b8147848156a7969e812368f28597a265f68965c0c48057", + "workspace_digest": "d89692495b79a09750d340fdf0f552ef89651a3e7b75a409d9adf4890456cef2", + "acceptance_input_digest": "99d27392ebbf304fa0b23e510a3a7f26f1c54cd9068221cc5b0f938a7bbc4c52", "acceptance_manifest": { "schema_version": 1, "entries": [ @@ -41,8 +41,8 @@ "path": ".github/workflows/trust.yml", "kind": "file", "mode": 33188, - "payload_digest": "f4fad2f8914de3e6285b1afce3dc3ebe624e657aecc3bb2312fd6c3003a76f7f", - "entry_digest": "a1f5ca04418295d7d3919880416b2166a40ca6b0ac527a83458ecf51d26d2788", + "payload_digest": "d3ff2130b2a23f1194aec1f408eb658a83857754af522360c50548669eba788b", + "entry_digest": "f1485f9e20ab4ad855620c42fe93ffdbc6217635580820877efdb996961802b1", "owners": [ "@exact:delivery" ] From c6d9326fd7f4c7925deb5ff4f27f984a073bf6b8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 18 Jul 2026 17:15:39 +0000 Subject: [PATCH 7/9] Rebind SpecSync acceptance evidence to the 5.0.1 CI pin Trust installs SpecSync 5.0.1; acceptance digests produced by 5.1.1 were rejected as stale. Re-verify and re-accept with 5.0.1 so the contract gate matches CI. Co-authored-by: Leif --- .github/workflows/trust.yml | 1 + .../approvals.json | 811 +----------------- .../deltas/aps-cli.md | 4 +- .../state.json | 3 +- .../verification.json | 365 +------- specs/aps-cli/aps-cli.spec.md | 3 +- specs/state-store/state-store.spec.md | 3 +- 7 files changed, 28 insertions(+), 1162 deletions(-) diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml index 9f9a75c..027c014 100644 --- a/.github/workflows/trust.yml +++ b/.github/workflows/trust.yml @@ -1,6 +1,7 @@ name: Trust # Private repo: CorvidLabs trust gate on macOS self-hosted runners. +# SpecSync acceptance evidence rebound with the Trust-pinned 5.0.1 CLI. # Revisit before making the repository public: fork PRs must not run on # self-hosted hosts. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json index f356cf5..2a45150 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json @@ -76,806 +76,27 @@ "timestamp": 1784394715, "digest": "bf47283138ee6da7f4434e6ff1ca9b7d34db666ea784474b36b45eec525f2ccc", "note": "Re-accept with Trust range workflow delivery fix." - } - ], - "reopenings": [ + }, { - "schema_version": 1, - "change_id": "CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts", + "gate": "definition", "actor": "leif algo", - "reason": "Companion context/testing/tasks files were finalized after first accept, making accepted delivery evidence stale.", - "timestamp": 1784393403, - "from_state": "accepted", - "to_state": "verifying", - "superseded_approval": { - "gate": "acceptance", - "actor": "leif algo", - "timestamp": 1784393368, - "digest": "6d19a3078f062938ee3e14692d1ed6694ceb70bdc794146a86108cc8c1de509b", - "note": "Accept after local verify green; CI awaits macOS self-hosted runners." - }, - "prior_verification": { - "timestamp": 1784393368, - "commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", - "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "workspace_digest": "c8511495beb59a1886f889207c2367c0cad3fa3efcba98a29d28ef1a1c5ddcd0", - "acceptance_input_digest": "e410fc1465ce16aa200e9d509f4455dc3cea215a8640e82d20608be2d58745c2", - "acceptance_manifest": { - "schema_version": 1, - "entries": [ - { - "path": ".attest.json", - "kind": "file", - "mode": 33188, - "payload_digest": "fda17571040ce10c378e009859f92cc33afd67b5c62d3f96510bf9e6e5de0a9f", - "entry_digest": "9d185be1f08f917f1162191bbd90ca325f047bec1cda66f2fc6d0737c08da1ab", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".augur.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "17f6ad5b84b4db012f0e3f398a96a478c1324fd47e72e1dd2a13c7cf9a432983", - "entry_digest": "bac13c952da05292bdd0af5849aad9d9def3ae5afc830fa42b6914b2fd874beb", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".github/workflows/ci.yml", - "kind": "file", - "mode": 33188, - "payload_digest": "1f310d5d11b4466aedf85aac75d7db13b07d564f1e38e2f596defb8cf2f06d1c", - "entry_digest": "9abaefb404d6bb884367be7ea7524e890c9bab326c810c0985569c35a83418e7", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".github/workflows/trust.yml", - "kind": "file", - "mode": 33188, - "payload_digest": "f4fad2f8914de3e6285b1afce3dc3ebe624e657aecc3bb2312fd6c3003a76f7f", - "entry_digest": "a1f5ca04418295d7d3919880416b2166a40ca6b0ac527a83458ecf51d26d2788", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".gitignore", - "kind": "file", - "mode": 33188, - "payload_digest": "30d23b531c3fcb3e46c413c3d06d3c2848bb273aaf86abdee660e201ed9519a9", - "entry_digest": "8c2aa3eee1fa32d85bddb1f5daf626a0a97ce920f434cd2ec57050fe1623867a", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/.gitignore", - "kind": "file", - "mode": 33188, - "payload_digest": "a3129d6f93250ade8dbacfc73bc7eeae0cc47c2f7032142ca47cb4f1ffb2483e", - "entry_digest": "9badbf40b83d05f58bafda0fc2cafccfe726e4da7e6e67ef513e822989e13f04", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/change-sequence.json", - "kind": "file", - "mode": 33188, - "payload_digest": "1f95d9c5ccca97dabb0fa17a4d2b2491023b263fb475e5a03e784eeb63f7232a", - "entry_digest": "f4b667fec7bde996c7c0f9b31f7ea84ddef37f171371f3e0084c0bb9a66978af", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/config.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "54a83f6a4a252649bac390d2e936aa0815711fba86b6bfc8ea8fff2fffdfd29b", - "entry_digest": "e60f979233a7db75ce63f4ef42d6f1f7676ad1655a438b9baf78558aba60ec3e", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/registry.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "c423be1a5cf87318f85dc252fe0acd1c1486c5224ddc2d8e19bea1ac9c69c820", - "entry_digest": "7e1f068900ced849b8d1028ca40165fbdc5280ae7f53452f0e57e2710d895848", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/sdd.json", - "kind": "file", - "mode": 33188, - "payload_digest": "2d5fb3058b1ee4ce584c3cda9410c193c4893e272ed459205e58bfde06afc7b0", - "entry_digest": "8c6b11fc5787eb04e7ee651eb15fbf98fc3ea22db37e65423e3d75f99c09df19", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/version", - "kind": "file", - "mode": 33188, - "payload_digest": "23b6867924dfeb9cf532753438dc919669bf93ad88215e11c15630a4acbf4299", - "entry_digest": "339b5f88be30302336707baa5dab61fd4b324d04e495d3bb772cf893fb4f73bc", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".trust.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "6284ced27613c8e2dd8266ffd1668f021cb24e1edb6ccd79c9ade86032c09ce8", - "entry_digest": "7cdd9144620ced58d9ac48ee7d2b8563f5564f1ae2db02a22e7eed781963257e", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "AGENTS.md", - "kind": "file", - "mode": 33188, - "payload_digest": "a671dd50eea50f115e6f9abd554e5a8ad7e520208fec5c4bd540c4f3a07ef807", - "entry_digest": "c321960d8ebbf18c2833c8f8b7fe413d6f0e349b424bf2b296a4da7a26316750", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "CLAUDE.md", - "kind": "file", - "mode": 33188, - "payload_digest": "e2df5028858a540821e4a666297d536a14bf598d48afe6c44df921b0f1ddbf32", - "entry_digest": "6930540d6a42ffd8c849bdf10eaf69c3f231cf5e824c9e6f0e694d3edb91bda3", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Package.resolved", - "kind": "file", - "mode": 33188, - "payload_digest": "12eea9fa129e151eaffdc230a234293407f0e3a99c52f15597c72e4e591c0e1e", - "entry_digest": "554d48ebe132641edab54e1d89d163cc2534521a9f41750ed5bd8582723a2d28", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Package.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", - "entry_digest": "0b185dd498f42e05a6cc8c2447d547432f4c40000c5dc26f17fe0fc7ae21d6cb", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "README.md", - "kind": "file", - "mode": 33188, - "payload_digest": "247d8f2d3f67cf9a7c3641ad26bc37a016fa4c7a637f8d0349864f85de6e6bad", - "entry_digest": "464275632b4b92467210ce1683caa823bd308fcc98cedf860e53da9e37d563a6", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Scripts/smoke.sh", - "kind": "file", - "mode": 33261, - "payload_digest": "5947d02b95d6205d63beca54876398d81226d0d4796b4234b646a3b919f08b4c", - "entry_digest": "a847aedf94fa22e35460140f14bdd4be567c550ddc2d20ade0f672329f3efbd7", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Sources/aps/Aps.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "17c9cb972eec5b29d19adf9ea64e125ef03d8bbfb8f5115e438a309c0a1d4316", - "entry_digest": "19304c7bb4daa894ed568d6ead0153390bc7011acf03d1d08addf0b3ac13e4a4", - "owners": [ - "aps-cli" - ] - }, - { - "path": "Sources/aps/DemoKey.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "f973ce1f86e31efd412a76938db78bbd36b01b6ee7dbb48a9865edb569917380", - "entry_digest": "5d391ca2c3462528b91a83888a6b09484f850995b504d01f61a31c91ec3a80db", - "owners": [ - "aps-cli" - ] - }, - { - "path": "Sources/aps/DemoState.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "036eed2ac58afdf87b30938911658abe74888fd3ca2c6a63869de3f5f2701125", - "entry_digest": "7dda9ef80f141fffd93dc5a6dfa9c41b5f2c7ce28265341e764b72269c687595", - "owners": [ - "state-store" - ] - }, - { - "path": "Sources/aps/Dependencies.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "635340259dcd618bf5099e07dad823f72f4517f6a2762ec1e6b67965221ccef2", - "entry_digest": "637ab3fca33111ebb5f145cdd632e7a6412e99d88d08e3890ab1cc3edc54c736", - "owners": [ - "state-store" - ] - }, - { - "path": "Sources/aps/StateStore.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "d6773947e8268bac77da4c323b541ef5fe514939d4ef0cafd74ecbd3a4a3ece3", - "entry_digest": "190b8e0e4aa74797e09b64e1576b3ddb5b57dcf991cd71a5951fe3e606803c08", - "owners": [ - "state-store" - ] - }, - { - "path": "Tests/apsTests/APSTests.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "55ac9e3657a48995bad11dfe75de46f9e367b3cf0a0250b90d685392d4e09a15", - "entry_digest": "388f64f61823bb9f78051c74227da3839f15955a8bae50b579003c5bc13fe78e", - "owners": [ - "@exact:test" - ] - }, - { - "path": "fledge.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "f69feb965265eb9481197160885409a03d0eb367149a2955c7b17a98dee9ba4e", - "entry_digest": "4994cce91eb6ed15dcf039ff4ce7194b901fe8e5ef33905503817173f42b6560", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "specs/aps-cli/aps-cli.spec.md", - "kind": "file", - "mode": 33188, - "payload_digest": "f5cc6d9e1f1f328b100b826707470577669dc24e46cc4f8f9d98164a2f0339a8", - "entry_digest": "07206127871185e01418a2f11a620743fcb70666abdcbcc895a8d0f8a88fd536", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/context.md", - "kind": "file", - "mode": 33188, - "payload_digest": "57d3395961e0cbe4ca7c02b638cd0e5da34214f3fd0c1342914eec6cccd3ff8c", - "entry_digest": "ccba3dc943b3128bef61641fe7c5b57c14393ad0e009353b6f86cd0446890fbf", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/requirements.md", - "kind": "file", - "mode": 33188, - "payload_digest": "6f0a119928aaded71476b059b3950aea3dfcc80d32a377857ed4b0ad5b1240a1", - "entry_digest": "fb8e378328b81db7a39be58a5e31c8627a99a63f834e92bc65062718c7caa69a", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/tasks.md", - "kind": "file", - "mode": 33188, - "payload_digest": "d4310391e8703dbcf632a37901ed8c65d0675e5830284325269e7fe371b6094f", - "entry_digest": "5e3171593d0abe547a27788401056cfce4f911383ef4526cc3f3bdc3150361e8", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/testing.md", - "kind": "file", - "mode": 33188, - "payload_digest": "d1b40f1198fb2b23d3452450afb5c84748d95c38efd81529213cb75cdc5071c9", - "entry_digest": "dab7bdb784204ee22cad510b0de8008ea539ca747419f3c818003deae04cbbd3", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/state-store/context.md", - "kind": "file", - "mode": 33188, - "payload_digest": "35090a0e0d4e0b10ac64cccd5f6346b7380ff6a5d6180ec732f12eb554c00bf7", - "entry_digest": "3df91075712a9b76bb0d810a76ab3bcb75f2518680c69356c843a166a2934691", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/requirements.md", - "kind": "file", - "mode": 33188, - "payload_digest": "1e877f271ce3b3794a5019b4321b6bf971ddf08bdf400a2e5405587c35a8f606", - "entry_digest": "92c4d1f84ee0874655e25e66422faa80470e7e0512e51124755fb6ed36ea6ef8", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/state-store.spec.md", - "kind": "file", - "mode": 33188, - "payload_digest": "1531480af30af3a268a1234b78346bced142443d04cd1e67b1488a2541404084", - "entry_digest": "875548708b0830fbce9aa616293cdacf7e89f2ac23d391aa85057fa8cf5ab24d", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/tasks.md", - "kind": "file", - "mode": 33188, - "payload_digest": "4a931c764c1b83ba70ead17a33f55aaf4356a367f600f10724b963b9d1c6ca92", - "entry_digest": "bd414350cad0fccf90e0acd9da163a4e7d4242a653bd9d6b475cd58530858666", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/testing.md", - "kind": "file", - "mode": 33188, - "payload_digest": "159bf0c984c3490f5f7da8704b9153f41f8bc2ced3ea43246123a72d5a3f7783", - "entry_digest": "dd51d33d0d6928c2f90459f02abe826ee4a95490baefcf4ace149a9fb2f47c91", - "owners": [ - "state-store" - ] - } - ] - }, - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-aps-cli-001", - "REQ-aps-cli-002", - "REQ-aps-cli-003", - "REQ-aps-cli-004", - "REQ-aps-cli-005", - "REQ-state-store-001", - "REQ-state-store-002", - "REQ-state-store-003", - "REQ-state-store-004" - ] - }, - "stale_acceptance_input_digest": "e410fc1465ce16aa200e9d509f4455dc3cea215a8640e82d20608be2d58745c2", - "current_acceptance_input_digest": "c712cc9484f9f9320b8147848156a7969e812368f28597a265f68965c0c48057" + "timestamp": 1784394921, + "digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", + "note": "Approve unchanged definition before 5.0.1 evidence rebind." }, { - "schema_version": 1, - "change_id": "CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts", + "gate": "definition", "actor": "leif algo", - "reason": "Trust workflow needs an explicit comparison range because tokenized checkout remotes are treated as external.", - "timestamp": 1784394701, - "from_state": "accepted", - "to_state": "verifying", - "superseded_approval": { - "gate": "acceptance", - "actor": "leif algo", - "timestamp": 1784393407, - "digest": "4145e1bdd5239a9d33b52c4208171b5d98be0b5ecc5e1d1e28451194cb689de8", - "note": "Re-accept with current companions and export tables." - }, - "prior_verification": { - "timestamp": 1784393406, - "commit": "d5f28efeb86135279b7a5ba8bed8894a2c290a35", - "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "workspace_digest": "617795e00f0d67a61a7059e8e4cd218dc16e0dd45f517e3bedbf55c83312d7fa", - "acceptance_input_digest": "c712cc9484f9f9320b8147848156a7969e812368f28597a265f68965c0c48057", - "acceptance_manifest": { - "schema_version": 1, - "entries": [ - { - "path": ".attest.json", - "kind": "file", - "mode": 33188, - "payload_digest": "fda17571040ce10c378e009859f92cc33afd67b5c62d3f96510bf9e6e5de0a9f", - "entry_digest": "9d185be1f08f917f1162191bbd90ca325f047bec1cda66f2fc6d0737c08da1ab", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".augur.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "17f6ad5b84b4db012f0e3f398a96a478c1324fd47e72e1dd2a13c7cf9a432983", - "entry_digest": "bac13c952da05292bdd0af5849aad9d9def3ae5afc830fa42b6914b2fd874beb", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".github/workflows/ci.yml", - "kind": "file", - "mode": 33188, - "payload_digest": "1f310d5d11b4466aedf85aac75d7db13b07d564f1e38e2f596defb8cf2f06d1c", - "entry_digest": "9abaefb404d6bb884367be7ea7524e890c9bab326c810c0985569c35a83418e7", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".github/workflows/trust.yml", - "kind": "file", - "mode": 33188, - "payload_digest": "f4fad2f8914de3e6285b1afce3dc3ebe624e657aecc3bb2312fd6c3003a76f7f", - "entry_digest": "a1f5ca04418295d7d3919880416b2166a40ca6b0ac527a83458ecf51d26d2788", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".gitignore", - "kind": "file", - "mode": 33188, - "payload_digest": "30d23b531c3fcb3e46c413c3d06d3c2848bb273aaf86abdee660e201ed9519a9", - "entry_digest": "8c2aa3eee1fa32d85bddb1f5daf626a0a97ce920f434cd2ec57050fe1623867a", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/.gitignore", - "kind": "file", - "mode": 33188, - "payload_digest": "a3129d6f93250ade8dbacfc73bc7eeae0cc47c2f7032142ca47cb4f1ffb2483e", - "entry_digest": "9badbf40b83d05f58bafda0fc2cafccfe726e4da7e6e67ef513e822989e13f04", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/change-sequence.json", - "kind": "file", - "mode": 33188, - "payload_digest": "1f95d9c5ccca97dabb0fa17a4d2b2491023b263fb475e5a03e784eeb63f7232a", - "entry_digest": "f4b667fec7bde996c7c0f9b31f7ea84ddef37f171371f3e0084c0bb9a66978af", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/config.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "54a83f6a4a252649bac390d2e936aa0815711fba86b6bfc8ea8fff2fffdfd29b", - "entry_digest": "e60f979233a7db75ce63f4ef42d6f1f7676ad1655a438b9baf78558aba60ec3e", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/registry.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "c423be1a5cf87318f85dc252fe0acd1c1486c5224ddc2d8e19bea1ac9c69c820", - "entry_digest": "7e1f068900ced849b8d1028ca40165fbdc5280ae7f53452f0e57e2710d895848", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/sdd.json", - "kind": "file", - "mode": 33188, - "payload_digest": "2d5fb3058b1ee4ce584c3cda9410c193c4893e272ed459205e58bfde06afc7b0", - "entry_digest": "8c6b11fc5787eb04e7ee651eb15fbf98fc3ea22db37e65423e3d75f99c09df19", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/version", - "kind": "file", - "mode": 33188, - "payload_digest": "23b6867924dfeb9cf532753438dc919669bf93ad88215e11c15630a4acbf4299", - "entry_digest": "339b5f88be30302336707baa5dab61fd4b324d04e495d3bb772cf893fb4f73bc", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".trust.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "6284ced27613c8e2dd8266ffd1668f021cb24e1edb6ccd79c9ade86032c09ce8", - "entry_digest": "7cdd9144620ced58d9ac48ee7d2b8563f5564f1ae2db02a22e7eed781963257e", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "AGENTS.md", - "kind": "file", - "mode": 33188, - "payload_digest": "a671dd50eea50f115e6f9abd554e5a8ad7e520208fec5c4bd540c4f3a07ef807", - "entry_digest": "c321960d8ebbf18c2833c8f8b7fe413d6f0e349b424bf2b296a4da7a26316750", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "CLAUDE.md", - "kind": "file", - "mode": 33188, - "payload_digest": "e2df5028858a540821e4a666297d536a14bf598d48afe6c44df921b0f1ddbf32", - "entry_digest": "6930540d6a42ffd8c849bdf10eaf69c3f231cf5e824c9e6f0e694d3edb91bda3", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Package.resolved", - "kind": "file", - "mode": 33188, - "payload_digest": "12eea9fa129e151eaffdc230a234293407f0e3a99c52f15597c72e4e591c0e1e", - "entry_digest": "554d48ebe132641edab54e1d89d163cc2534521a9f41750ed5bd8582723a2d28", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Package.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", - "entry_digest": "0b185dd498f42e05a6cc8c2447d547432f4c40000c5dc26f17fe0fc7ae21d6cb", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "README.md", - "kind": "file", - "mode": 33188, - "payload_digest": "247d8f2d3f67cf9a7c3641ad26bc37a016fa4c7a637f8d0349864f85de6e6bad", - "entry_digest": "464275632b4b92467210ce1683caa823bd308fcc98cedf860e53da9e37d563a6", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Scripts/smoke.sh", - "kind": "file", - "mode": 33261, - "payload_digest": "5947d02b95d6205d63beca54876398d81226d0d4796b4234b646a3b919f08b4c", - "entry_digest": "a847aedf94fa22e35460140f14bdd4be567c550ddc2d20ade0f672329f3efbd7", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Sources/aps/Aps.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "17c9cb972eec5b29d19adf9ea64e125ef03d8bbfb8f5115e438a309c0a1d4316", - "entry_digest": "19304c7bb4daa894ed568d6ead0153390bc7011acf03d1d08addf0b3ac13e4a4", - "owners": [ - "aps-cli" - ] - }, - { - "path": "Sources/aps/DemoKey.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "f973ce1f86e31efd412a76938db78bbd36b01b6ee7dbb48a9865edb569917380", - "entry_digest": "5d391ca2c3462528b91a83888a6b09484f850995b504d01f61a31c91ec3a80db", - "owners": [ - "aps-cli" - ] - }, - { - "path": "Sources/aps/DemoState.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "036eed2ac58afdf87b30938911658abe74888fd3ca2c6a63869de3f5f2701125", - "entry_digest": "7dda9ef80f141fffd93dc5a6dfa9c41b5f2c7ce28265341e764b72269c687595", - "owners": [ - "state-store" - ] - }, - { - "path": "Sources/aps/Dependencies.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "635340259dcd618bf5099e07dad823f72f4517f6a2762ec1e6b67965221ccef2", - "entry_digest": "637ab3fca33111ebb5f145cdd632e7a6412e99d88d08e3890ab1cc3edc54c736", - "owners": [ - "state-store" - ] - }, - { - "path": "Sources/aps/StateStore.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "d6773947e8268bac77da4c323b541ef5fe514939d4ef0cafd74ecbd3a4a3ece3", - "entry_digest": "190b8e0e4aa74797e09b64e1576b3ddb5b57dcf991cd71a5951fe3e606803c08", - "owners": [ - "state-store" - ] - }, - { - "path": "Tests/apsTests/APSTests.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "55ac9e3657a48995bad11dfe75de46f9e367b3cf0a0250b90d685392d4e09a15", - "entry_digest": "388f64f61823bb9f78051c74227da3839f15955a8bae50b579003c5bc13fe78e", - "owners": [ - "@exact:test" - ] - }, - { - "path": "fledge.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "f69feb965265eb9481197160885409a03d0eb367149a2955c7b17a98dee9ba4e", - "entry_digest": "4994cce91eb6ed15dcf039ff4ce7194b901fe8e5ef33905503817173f42b6560", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "specs/aps-cli/aps-cli.spec.md", - "kind": "file", - "mode": 33188, - "payload_digest": "f5cc6d9e1f1f328b100b826707470577669dc24e46cc4f8f9d98164a2f0339a8", - "entry_digest": "07206127871185e01418a2f11a620743fcb70666abdcbcc895a8d0f8a88fd536", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/context.md", - "kind": "file", - "mode": 33188, - "payload_digest": "6a67354ec782d88510bea4b0ec28e1b1a3c50fc01e625ee32d6783f4dfbc86e0", - "entry_digest": "9cb95bb0d687799ba10637230b404cbef8a5abfb45d46a07a7bb50bee9703431", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/requirements.md", - "kind": "file", - "mode": 33188, - "payload_digest": "683b7544c36c0a73b5a62ebdad6888f68488e0f3a31aed479f3cc5b81635c0ad", - "entry_digest": "9173ab3068d73f055b46c7b896e6de1241582da3162e2365ba59367a28fce056", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/tasks.md", - "kind": "file", - "mode": 33188, - "payload_digest": "b6f0c8e3aa90f43e5dc40389e77088b2ec6ebb725c89c57217970fc1c221f527", - "entry_digest": "af31087c96d633274df81aecd4e99f520a55995882545190d2d42bb30fa5c3aa", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/testing.md", - "kind": "file", - "mode": 33188, - "payload_digest": "14420af80f34d7954894aaf63f9864db13eea74549796043f54badf82805394a", - "entry_digest": "1227fad23fad49d312453dfe8fffc2bfe67396fdb29c88dab355bd60e8ec91b5", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/state-store/context.md", - "kind": "file", - "mode": 33188, - "payload_digest": "ddb4564d168db43eadd6315a7f56b532198905a79abebfee77db890db0f9c402", - "entry_digest": "a14edf94507dfd13d7d325bf68e370e0c1646e323b28341bd0c1dfff72f05d88", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/requirements.md", - "kind": "file", - "mode": 33188, - "payload_digest": "713553c4b9f57ec521c060f1e191963f15c8c6a82a55e33ed0730538b6b2ee8d", - "entry_digest": "aa26dc21220beeea694456c16a04ed4fe9cf7db95c3d52ae911b8f18dc02e049", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/state-store.spec.md", - "kind": "file", - "mode": 33188, - "payload_digest": "1531480af30af3a268a1234b78346bced142443d04cd1e67b1488a2541404084", - "entry_digest": "875548708b0830fbce9aa616293cdacf7e89f2ac23d391aa85057fa8cf5ab24d", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/tasks.md", - "kind": "file", - "mode": 33188, - "payload_digest": "711db2a24a4959531ca966ac43d96e7817788ebe74077280a6cff950cb9a8779", - "entry_digest": "8402318068cd8ab6f8a596519289e70425dbc28bf6b31d5c1ef6f0a17f927f74", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/testing.md", - "kind": "file", - "mode": 33188, - "payload_digest": "96fbc44cdbe25dfab52a47f8efdbd4698203571981b181c78a04769112402f1d", - "entry_digest": "8b0abd2a0f6613b9caa1f2831cdf8776b80a1945552eade241ff3d3b8d6404af", - "owners": [ - "state-store" - ] - } - ] - }, - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-aps-cli-001", - "REQ-aps-cli-002", - "REQ-aps-cli-003", - "REQ-aps-cli-004", - "REQ-aps-cli-005", - "REQ-state-store-001", - "REQ-state-store-002", - "REQ-state-store-003", - "REQ-state-store-004" - ] - }, - "stale_acceptance_input_digest": "c712cc9484f9f9320b8147848156a7969e812368f28597a265f68965c0c48057", - "current_acceptance_input_digest": "99d27392ebbf304fa0b23e510a3a7f26f1c54cd9068221cc5b0f938a7bbc4c52" + "timestamp": 1784394931, + "digest": "6c81bf7ec50ac551292c3a5ade4785a61736c5b608ff255d0e14e8a24c3f619f", + "note": "Approve delta fix: REQ-aps-cli-005 is MODIFIED on re-accept." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784394935, + "digest": "ab2e8e65c3b94ebfde36bcafe2bab2d40be3020b702c363ef38dbb218c355f1e", + "note": "Accept with SpecSync 5.0.1 digests matching Trust CI." } ] } diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md index ece9fd3..4b35479 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md @@ -1,6 +1,6 @@ # APS CLI contract introduction -## ADDED +## MODIFIED ### REQUIREMENT REQ-aps-cli-005 @@ -10,8 +10,6 @@ Acceptance Criteria - Each case is reachable from CLI or StateStore coding paths. - `description` is suitable for ValidationError bridging. -## MODIFIED - ### REQUIREMENT REQ-aps-cli-001 The CLI SHALL expose get, set, watch, dump, keys, and reset over the fixed `DemoKey` schema covering `counter`, `message`, `flag`, and `note`. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json index 5b061d4..4b19d8b 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json @@ -6,10 +6,9 @@ "description": "Adopt CorvidLabs trust and establish aps module contracts", "kind": "migration", "state": "accepted", - "canonical_applied": true, "base_commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", "created_at": 1784393134, - "updated_at": 1784394715, + "updated_at": 1784394935, "affected_specs": [ "aps-cli", "state-store" diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json index 947c237..21866b4 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json +++ b/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json @@ -1,364 +1,9 @@ { - "timestamp": 1784394714, - "commit": "fbcb4636cc4a05c7c21da5342042ec9d541d90db", - "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "workspace_digest": "d89692495b79a09750d340fdf0f552ef89651a3e7b75a409d9adf4890456cef2", - "acceptance_input_digest": "99d27392ebbf304fa0b23e510a3a7f26f1c54cd9068221cc5b0f938a7bbc4c52", - "acceptance_manifest": { - "schema_version": 1, - "entries": [ - { - "path": ".attest.json", - "kind": "file", - "mode": 33188, - "payload_digest": "fda17571040ce10c378e009859f92cc33afd67b5c62d3f96510bf9e6e5de0a9f", - "entry_digest": "9d185be1f08f917f1162191bbd90ca325f047bec1cda66f2fc6d0737c08da1ab", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".augur.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "17f6ad5b84b4db012f0e3f398a96a478c1324fd47e72e1dd2a13c7cf9a432983", - "entry_digest": "bac13c952da05292bdd0af5849aad9d9def3ae5afc830fa42b6914b2fd874beb", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".github/workflows/ci.yml", - "kind": "file", - "mode": 33188, - "payload_digest": "1f310d5d11b4466aedf85aac75d7db13b07d564f1e38e2f596defb8cf2f06d1c", - "entry_digest": "9abaefb404d6bb884367be7ea7524e890c9bab326c810c0985569c35a83418e7", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".github/workflows/trust.yml", - "kind": "file", - "mode": 33188, - "payload_digest": "d3ff2130b2a23f1194aec1f408eb658a83857754af522360c50548669eba788b", - "entry_digest": "f1485f9e20ab4ad855620c42fe93ffdbc6217635580820877efdb996961802b1", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".gitignore", - "kind": "file", - "mode": 33188, - "payload_digest": "30d23b531c3fcb3e46c413c3d06d3c2848bb273aaf86abdee660e201ed9519a9", - "entry_digest": "8c2aa3eee1fa32d85bddb1f5daf626a0a97ce920f434cd2ec57050fe1623867a", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/.gitignore", - "kind": "file", - "mode": 33188, - "payload_digest": "a3129d6f93250ade8dbacfc73bc7eeae0cc47c2f7032142ca47cb4f1ffb2483e", - "entry_digest": "9badbf40b83d05f58bafda0fc2cafccfe726e4da7e6e67ef513e822989e13f04", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/change-sequence.json", - "kind": "file", - "mode": 33188, - "payload_digest": "1f95d9c5ccca97dabb0fa17a4d2b2491023b263fb475e5a03e784eeb63f7232a", - "entry_digest": "f4b667fec7bde996c7c0f9b31f7ea84ddef37f171371f3e0084c0bb9a66978af", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/config.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "54a83f6a4a252649bac390d2e936aa0815711fba86b6bfc8ea8fff2fffdfd29b", - "entry_digest": "e60f979233a7db75ce63f4ef42d6f1f7676ad1655a438b9baf78558aba60ec3e", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/registry.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "c423be1a5cf87318f85dc252fe0acd1c1486c5224ddc2d8e19bea1ac9c69c820", - "entry_digest": "7e1f068900ced849b8d1028ca40165fbdc5280ae7f53452f0e57e2710d895848", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/sdd.json", - "kind": "file", - "mode": 33188, - "payload_digest": "2d5fb3058b1ee4ce584c3cda9410c193c4893e272ed459205e58bfde06afc7b0", - "entry_digest": "8c6b11fc5787eb04e7ee651eb15fbf98fc3ea22db37e65423e3d75f99c09df19", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".specsync/version", - "kind": "file", - "mode": 33188, - "payload_digest": "23b6867924dfeb9cf532753438dc919669bf93ad88215e11c15630a4acbf4299", - "entry_digest": "339b5f88be30302336707baa5dab61fd4b324d04e495d3bb772cf893fb4f73bc", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": ".trust.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "6284ced27613c8e2dd8266ffd1668f021cb24e1edb6ccd79c9ade86032c09ce8", - "entry_digest": "7cdd9144620ced58d9ac48ee7d2b8563f5564f1ae2db02a22e7eed781963257e", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "AGENTS.md", - "kind": "file", - "mode": 33188, - "payload_digest": "a671dd50eea50f115e6f9abd554e5a8ad7e520208fec5c4bd540c4f3a07ef807", - "entry_digest": "c321960d8ebbf18c2833c8f8b7fe413d6f0e349b424bf2b296a4da7a26316750", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "CLAUDE.md", - "kind": "file", - "mode": 33188, - "payload_digest": "e2df5028858a540821e4a666297d536a14bf598d48afe6c44df921b0f1ddbf32", - "entry_digest": "6930540d6a42ffd8c849bdf10eaf69c3f231cf5e824c9e6f0e694d3edb91bda3", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Package.resolved", - "kind": "file", - "mode": 33188, - "payload_digest": "12eea9fa129e151eaffdc230a234293407f0e3a99c52f15597c72e4e591c0e1e", - "entry_digest": "554d48ebe132641edab54e1d89d163cc2534521a9f41750ed5bd8582723a2d28", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Package.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", - "entry_digest": "0b185dd498f42e05a6cc8c2447d547432f4c40000c5dc26f17fe0fc7ae21d6cb", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "README.md", - "kind": "file", - "mode": 33188, - "payload_digest": "247d8f2d3f67cf9a7c3641ad26bc37a016fa4c7a637f8d0349864f85de6e6bad", - "entry_digest": "464275632b4b92467210ce1683caa823bd308fcc98cedf860e53da9e37d563a6", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Scripts/smoke.sh", - "kind": "file", - "mode": 33261, - "payload_digest": "5947d02b95d6205d63beca54876398d81226d0d4796b4234b646a3b919f08b4c", - "entry_digest": "a847aedf94fa22e35460140f14bdd4be567c550ddc2d20ade0f672329f3efbd7", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "Sources/aps/Aps.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "17c9cb972eec5b29d19adf9ea64e125ef03d8bbfb8f5115e438a309c0a1d4316", - "entry_digest": "19304c7bb4daa894ed568d6ead0153390bc7011acf03d1d08addf0b3ac13e4a4", - "owners": [ - "aps-cli" - ] - }, - { - "path": "Sources/aps/DemoKey.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "f973ce1f86e31efd412a76938db78bbd36b01b6ee7dbb48a9865edb569917380", - "entry_digest": "5d391ca2c3462528b91a83888a6b09484f850995b504d01f61a31c91ec3a80db", - "owners": [ - "aps-cli" - ] - }, - { - "path": "Sources/aps/DemoState.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "036eed2ac58afdf87b30938911658abe74888fd3ca2c6a63869de3f5f2701125", - "entry_digest": "7dda9ef80f141fffd93dc5a6dfa9c41b5f2c7ce28265341e764b72269c687595", - "owners": [ - "state-store" - ] - }, - { - "path": "Sources/aps/Dependencies.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "635340259dcd618bf5099e07dad823f72f4517f6a2762ec1e6b67965221ccef2", - "entry_digest": "637ab3fca33111ebb5f145cdd632e7a6412e99d88d08e3890ab1cc3edc54c736", - "owners": [ - "state-store" - ] - }, - { - "path": "Sources/aps/StateStore.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "d6773947e8268bac77da4c323b541ef5fe514939d4ef0cafd74ecbd3a4a3ece3", - "entry_digest": "190b8e0e4aa74797e09b64e1576b3ddb5b57dcf991cd71a5951fe3e606803c08", - "owners": [ - "state-store" - ] - }, - { - "path": "Tests/apsTests/APSTests.swift", - "kind": "file", - "mode": 33188, - "payload_digest": "55ac9e3657a48995bad11dfe75de46f9e367b3cf0a0250b90d685392d4e09a15", - "entry_digest": "388f64f61823bb9f78051c74227da3839f15955a8bae50b579003c5bc13fe78e", - "owners": [ - "@exact:test" - ] - }, - { - "path": "fledge.toml", - "kind": "file", - "mode": 33188, - "payload_digest": "f69feb965265eb9481197160885409a03d0eb367149a2955c7b17a98dee9ba4e", - "entry_digest": "4994cce91eb6ed15dcf039ff4ce7194b901fe8e5ef33905503817173f42b6560", - "owners": [ - "@exact:delivery" - ] - }, - { - "path": "specs/aps-cli/aps-cli.spec.md", - "kind": "file", - "mode": 33188, - "payload_digest": "f5cc6d9e1f1f328b100b826707470577669dc24e46cc4f8f9d98164a2f0339a8", - "entry_digest": "07206127871185e01418a2f11a620743fcb70666abdcbcc895a8d0f8a88fd536", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/context.md", - "kind": "file", - "mode": 33188, - "payload_digest": "6a67354ec782d88510bea4b0ec28e1b1a3c50fc01e625ee32d6783f4dfbc86e0", - "entry_digest": "9cb95bb0d687799ba10637230b404cbef8a5abfb45d46a07a7bb50bee9703431", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/requirements.md", - "kind": "file", - "mode": 33188, - "payload_digest": "683b7544c36c0a73b5a62ebdad6888f68488e0f3a31aed479f3cc5b81635c0ad", - "entry_digest": "9173ab3068d73f055b46c7b896e6de1241582da3162e2365ba59367a28fce056", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/tasks.md", - "kind": "file", - "mode": 33188, - "payload_digest": "b6f0c8e3aa90f43e5dc40389e77088b2ec6ebb725c89c57217970fc1c221f527", - "entry_digest": "af31087c96d633274df81aecd4e99f520a55995882545190d2d42bb30fa5c3aa", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/aps-cli/testing.md", - "kind": "file", - "mode": 33188, - "payload_digest": "14420af80f34d7954894aaf63f9864db13eea74549796043f54badf82805394a", - "entry_digest": "1227fad23fad49d312453dfe8fffc2bfe67396fdb29c88dab355bd60e8ec91b5", - "owners": [ - "aps-cli" - ] - }, - { - "path": "specs/state-store/context.md", - "kind": "file", - "mode": 33188, - "payload_digest": "ddb4564d168db43eadd6315a7f56b532198905a79abebfee77db890db0f9c402", - "entry_digest": "a14edf94507dfd13d7d325bf68e370e0c1646e323b28341bd0c1dfff72f05d88", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/requirements.md", - "kind": "file", - "mode": 33188, - "payload_digest": "713553c4b9f57ec521c060f1e191963f15c8c6a82a55e33ed0730538b6b2ee8d", - "entry_digest": "aa26dc21220beeea694456c16a04ed4fe9cf7db95c3d52ae911b8f18dc02e049", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/state-store.spec.md", - "kind": "file", - "mode": 33188, - "payload_digest": "1531480af30af3a268a1234b78346bced142443d04cd1e67b1488a2541404084", - "entry_digest": "875548708b0830fbce9aa616293cdacf7e89f2ac23d391aa85057fa8cf5ab24d", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/tasks.md", - "kind": "file", - "mode": 33188, - "payload_digest": "711db2a24a4959531ca966ac43d96e7817788ebe74077280a6cff950cb9a8779", - "entry_digest": "8402318068cd8ab6f8a596519289e70425dbc28bf6b31d5c1ef6f0a17f927f74", - "owners": [ - "state-store" - ] - }, - { - "path": "specs/state-store/testing.md", - "kind": "file", - "mode": 33188, - "payload_digest": "96fbc44cdbe25dfab52a47f8efdbd4698203571981b181c78a04769112402f1d", - "entry_digest": "8b0abd2a0f6613b9caa1f2831cdf8776b80a1945552eade241ff3d3b8d6404af", - "owners": [ - "state-store" - ] - } - ] - }, + "timestamp": 1784394935, + "commit": "ae4cf265007ab3b0a1f608fb39842f4c3d88643c", + "contract_digest": "6c81bf7ec50ac551292c3a5ade4785a61736c5b608ff255d0e14e8a24c3f619f", + "workspace_digest": "1ec4a925a8103e9cf0dfca8bb0c014d71042ebdbb0f2774e2f9045a881b273e9", + "acceptance_input_digest": "6bf300a24272865455b0e19b6e1e9016e913a9afbe59e19999778b7b2e62ad0f", "passed": true, "commands": [ { diff --git a/specs/aps-cli/aps-cli.spec.md b/specs/aps-cli/aps-cli.spec.md index 158ea1c..7b42df6 100644 --- a/specs/aps-cli/aps-cli.spec.md +++ b/specs/aps-cli/aps-cli.spec.md @@ -1,6 +1,6 @@ --- module: aps-cli -version: 3 +version: 4 status: active files: - Sources/aps/Aps.swift @@ -96,3 +96,4 @@ Then the watcher prints `changed` within one poll interval. - 1: Initial CLI contract for get/set/watch/dump/keys/reset over the fixed demo schema. - 2: Explicit export inventory for SpecSync active-contract checks (`DemoKey`, `APSError`). | 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | +| 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | diff --git a/specs/state-store/state-store.spec.md b/specs/state-store/state-store.spec.md index 03b3d7c..2dc56e3 100644 --- a/specs/state-store/state-store.spec.md +++ b/specs/state-store/state-store.spec.md @@ -1,6 +1,6 @@ --- module: state-store -version: 3 +version: 4 status: active files: - Sources/aps/StateStore.swift @@ -94,3 +94,4 @@ Then keys include message with value "hi" and a timestamp field exists. - 1: Initial StateStore / Application demo-state contract for the aps CLI. - 2: Explicit export inventory for SpecSync active-contract checks. | 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | +| 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | From 8a76d01878593200ff1f1ba2104fea12a30db083 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 18 Jul 2026 17:37:42 +0000 Subject: [PATCH 8/9] Fix FileState watch cache, path isolation, and persistence errors Address PR review: poll note.json directly so cross-process watch works, configure FileState paths from CLI boot only, and fail set note when the on-disk value does not persist. Specs/README updated; CHG-0002 accepted. Co-authored-by: Leif --- .../approvals.json | 21 +++++++ .../change.md | 0 .../context.md | 0 .../deltas/aps-cli.md | 12 ++-- .../deltas/state-store.md | 19 ++++--- .../design.md | 0 .../docs.md | 0 .../plan.md | 0 .../requirements.md | 0 .../research.md | 0 .../state.json | 4 +- .../tasks.md | 0 .../testing.md | 6 +- .../verification-attempts.json | 0 .../verification.json | 10 ++-- .specsync/change-sequence.json | 4 +- .../approvals.json | 46 ++++++++++++++++ .../change.md | 25 +++++++++ .../context.md | 16 ++++++ .../deltas/aps-cli.md | 43 +++++++++++++++ .../deltas/state-store.md | 53 ++++++++++++++++++ .../design.md | 12 ++++ .../docs.md | 9 +++ .../plan.md | 12 ++++ .../requirements.md | 9 +++ .../state.json | 55 +++++++++++++++++++ .../tasks.md | 12 ++++ .../testing.md | 22 ++++++++ .../verification.json | 22 ++++++++ README.md | 6 +- Sources/aps/Aps.swift | 1 + Sources/aps/DemoKey.swift | 3 + Sources/aps/DemoState.swift | 3 + Sources/aps/StateStore.swift | 40 +++++++++++++- Tests/apsTests/APSTests.swift | 47 ++++++++++++++++ specs/aps-cli/aps-cli.spec.md | 10 +++- specs/aps-cli/requirements.md | 9 +-- specs/state-store/requirements.md | 10 ++-- specs/state-store/state-store.spec.md | 15 +++-- 39 files changed, 510 insertions(+), 46 deletions(-) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/approvals.json (81%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/change.md (100%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/context.md (100%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/deltas/aps-cli.md (83%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/deltas/state-store.md (63%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/design.md (100%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/docs.md (100%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/plan.md (100%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/requirements.md (100%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/research.md (100%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/state.json (96%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/tasks.md (100%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/testing.md (88%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/verification-attempts.json (100%) rename .specsync/{changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts => archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts}/verification.json (52%) create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/approvals.json create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/change.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/context.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/deltas/aps-cli.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/deltas/state-store.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/design.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/docs.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/plan.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/requirements.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/state.json create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/tasks.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/testing.md create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification.json diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json similarity index 81% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json index 2a45150..c042cc7 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json +++ b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json @@ -97,6 +97,27 @@ "timestamp": 1784394935, "digest": "ab2e8e65c3b94ebfde36bcafe2bab2d40be3020b702c363ef38dbb218c355f1e", "note": "Accept with SpecSync 5.0.1 digests matching Trust CI." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784396118, + "digest": "6c81bf7ec50ac551292c3a5ade4785a61736c5b608ff255d0e14e8a24c3f619f", + "note": "Re-approve unchanged CHG-0001 definition for evidence refresh." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784396140, + "digest": "aaee4b8c2c21511270edf4281c2222eeccf2561cf9e6d6462ea0aac6aa26f379", + "note": "Align CHG-0001 deltas with CHG-0002 FileState watch fixes for effective-contract verify." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784396144, + "digest": "769752daa1b9594322e9303509eae744ffdcefdff2ff4d8eabc84b897477a59f", + "note": "Accept refreshed CHG-0001 evidence with current FileState contracts." } ] } diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md similarity index 100% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md similarity index 100% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md similarity index 83% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md index 4b35479..9ff2d8a 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md +++ b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md @@ -4,11 +4,11 @@ ### REQUIREMENT REQ-aps-cli-005 -`APSError` SHALL cover `unknownKey`, `invalidValue`, `encodingFailed`, and `decodingFailed`. +`APSError` SHALL cover `unknownKey`, `invalidValue`, `encodingFailed`, `decodingFailed`, and `persistenceFailed`. Acceptance Criteria -- Each case is reachable from CLI or StateStore coding paths. -- `description` is suitable for ValidationError bridging. +- Each case has an actionable `description`. +- `set note` surfaces `persistenceFailed` when the on-disk value does not match after write. ### REQUIREMENT REQ-aps-cli-001 @@ -37,11 +37,12 @@ Acceptance Criteria ### REQUIREMENT REQ-aps-cli-004 -`watch` SHALL print the current value first and flush subsequent distinct values promptly. +`watch` SHALL print the current value first and flush subsequent distinct values promptly, including cross-process `FileState` writes to `note`. Acceptance Criteria - The first emitted line is the current value. - Non-TTY stdout still surfaces each change without waiting for process exit. +- An external write to `note.json` is observed within one poll interval without relying on AppState's FileState cache. ### SPEC SECTION Public API @@ -57,10 +58,11 @@ Acceptance Criteria | `invalidValue` | Value could not parse for the key type. | | `encodingFailed` | UTF-8 JSON encode failure. | | `decodingFailed` | UTF-8 JSON decode failure. | +| `persistenceFailed` | Disk-backed key did not persist after write. | | `storage` | Human storage kind (`State` / `StoredState` / `FileState`). | | `valueType` | Human value type (`Int` / `String` / `Bool`). | | `helpSummary` | Tab-separated key/type/storage columns for `keys`. | | `detail` | One-line description for `keys`. | | `description` | Actionable error text for humans and ValidationError bridging. | -Command tree (informational): `Aps` is the `@main` root (`ParsableCommand`) with get, set, watch, dump, keys, and reset / reset --all. +Command tree (informational): `Aps` is the `@main` root (`ParsableCommand`) with get, set, watch, dump, keys, and reset / reset --all. CLI `boot()` calls `APSPaths.configure()`. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md similarity index 63% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md index 8e5ced9..1690c98 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md +++ b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md @@ -4,11 +4,12 @@ ### REQUIREMENT REQ-state-store-001 -`StateStore` SHALL read and write demo keys through AppState Application extensions on the main actor via `init`, `get`, and `set`. +`StateStore` SHALL read and write demo keys through AppState Application extensions on the main actor via `init`, `get`, and `set`, without overwriting an injected `FileManager.defaultFileStatePath`. Acceptance Criteria - `get`/`set` round-trip `counter`, `message`, `flag`, and `note`. - Mutating paths are MainActor-isolated. +- `init` loads dependencies only; CLI `boot()` (or tests) configure FileState paths. ### REQUIREMENT REQ-state-store-002 @@ -20,19 +21,20 @@ Acceptance Criteria ### REQUIREMENT REQ-state-store-003 -Writing `flag` SHALL flush UserDefaults so Linux short-lived processes persist StoredState; `reset` / `resetAll` restore initials. +Writing `flag` SHALL flush UserDefaults so Linux short-lived processes persist StoredState; writing `note` SHALL verify the on-disk value and throw `APSError.persistenceFailed` when persistence fails; `reset` / `resetAll` restore initials. Acceptance Criteria - After `set(.flag, "true")`, a new `StateStore` instance observes true. +- After a successful `set(.note, ...)`, `readNoteFromDisk()` returns the same value. - `reset(.flag)` restores false and flushes. ### REQUIREMENT REQ-state-store-004 -`watchBlocking` SHALL combine Observation with RunLoop polling and honor `shouldContinue`; `parseBool` accepts common truthy/falsey tokens. +`watchBlocking` SHALL combine Observation with RunLoop polling and honor `shouldContinue`; for `note`, polling SHALL read the file directly so cross-process writes are visible despite AppState FileState caching; `parseBool` accepts common truthy/falsey tokens. Acceptance Criteria - In-process `State` mutations are observed. -- `FileState` mutations performed during the loop are observed. +- External writes to `note.json` are observed without updating AppState's cache. - `shouldContinue` false stops the loop without requiring Ctrl-C. ### SPEC SECTION Public API @@ -43,16 +45,17 @@ Acceptance Criteria | `APSClock` | Clock protocol for dump timestamps. | | `SystemAPSClock` | Production `APSClock` backed by `Date()`. | | `JSONCoding` | Shared pretty JSON helpers. | -| `init` | Configures FileState path and loads clock/jsonCoding dependencies. | +| `init` | Loads clock/jsonCoding dependencies without forcing `~/.aps`. | | `get` | Return the string form of a demo key. | -| `set` | Parse and write; throw `APSError.invalidValue` on bad input. | +| `set` | Parse and write; throw `APSError.invalidValue` or `persistenceFailed` on failure. | | `reset` | Restore one key to its AppState initial value. | | `resetAll` | Restore every demo key. | | `dump` | Pretty JSON snapshot using `@AppDependency` clock + jsonCoding. | -| `watchBlocking` | Observation + RunLoop poll loop with `shouldContinue`. | +| `watchBlocking` | Observation + RunLoop poll loop; `note` polls via direct disk read. | | `parseBool` | Accept true/false/1/0/yes/no/on/off (case-insensitive). | | `now` | Current `Date` from an `APSClock`. | | `encodePretty` | Encode an `Encodable` value as pretty UTF-8 JSON text. | | `decode` | Decode a `Decodable` value from UTF-8 JSON text. | +| `readNoteFromDisk` | Read `note.json` without touching AppState's FileState cache. | -Application demo surface (informational): `Application.counter` / `message` / `flag` / `note` / `clock` / `jsonCoding`, with `APSPaths.configure()` pointing FileState at `~/.aps`. +Application demo surface (informational): `Application.counter` / `message` / `flag` / `note` / `clock` / `jsonCoding`. `APSPaths.configure()` is invoked from CLI `boot()`, not `StateStore.init`. diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md similarity index 100% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md similarity index 100% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md similarity index 100% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md similarity index 100% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md similarity index 100% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json similarity index 96% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json index 4b19d8b..414a5df 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json +++ b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json @@ -5,10 +5,10 @@ "title": "Adopt CorvidLabs trust and establish aps module contracts", "description": "Adopt CorvidLabs trust and establish aps module contracts", "kind": "migration", - "state": "accepted", + "state": "archived", "base_commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", "created_at": 1784393134, - "updated_at": 1784394935, + "updated_at": 1784396144, "affected_specs": [ "aps-cli", "state-store" diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md similarity index 100% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md similarity index 88% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md index c37ab9b..27ff6cc 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md +++ b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md @@ -12,15 +12,15 @@ artifact: testing | REQ-aps-cli-001 | `testDemoKeyMetadata`, `testDemoKeyHelpSummaryFormat`, `Scripts/smoke.sh` keys | | REQ-aps-cli-002 | `testInvalidCounterValue`, `testInvalidFlagValue`, `testAPSErrorDescriptionsAreActionable` | | REQ-aps-cli-003 | `testProcessLocalStateKeysDoNotClaimCrossProcessPersistence`, `testFlagPersistsAcrossStateStoreInstances`, smoke flag/note | -| REQ-aps-cli-004 | `testWatchDetectsInProcessStateChange`, `testWatchDetectsFileStateChange` | +| REQ-aps-cli-004 | `testWatchDetectsInProcessStateChange`, `testWatchDetectsFileStateChange`, `testWatchDetectsExternalFileStateWrite` | | REQ-aps-cli-005 | `testAPSErrorDescriptionsAreActionable`, `testInvalidCounterValue` | | REQ-state-store-001 | `testCounterRoundTrip`, `testMessageAndFlagRoundTrip`, `testNoteFileStateRoundTrip` | | REQ-state-store-002 | `testDumpIncludesKeysAndUsesDependency`, `testJSONCodingDependency`, `testClockDependencyIsInjectable` | | REQ-state-store-003 | `testFlagPersistsAcrossStateStoreInstances`, `testResetRestoresInitialValues`, `testResetAll` | -| REQ-state-store-004 | `testWatchDetectsInProcessStateChange`, `testWatchDetectsFileStateChange`, `testParseBool` | +| REQ-state-store-004 | `testWatchDetectsInProcessStateChange`, `testWatchDetectsExternalFileStateWrite`, `testParseBool` | ## Gate evidence -- `swift test` (18 tests) +- `swift test` (20 tests) - `./Scripts/smoke.sh` - `fledge lanes run verify` diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json similarity index 100% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json diff --git a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json similarity index 52% rename from .specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json rename to .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json index 21866b4..affdcaf 100644 --- a/.specsync/changes/CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json +++ b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json @@ -1,9 +1,9 @@ { - "timestamp": 1784394935, - "commit": "ae4cf265007ab3b0a1f608fb39842f4c3d88643c", - "contract_digest": "6c81bf7ec50ac551292c3a5ade4785a61736c5b608ff255d0e14e8a24c3f619f", - "workspace_digest": "1ec4a925a8103e9cf0dfca8bb0c014d71042ebdbb0f2774e2f9045a881b273e9", - "acceptance_input_digest": "6bf300a24272865455b0e19b6e1e9016e913a9afbe59e19999778b7b2e62ad0f", + "timestamp": 1784396144, + "commit": "c6d9326fd7f4c7925deb5ff4f27f984a073bf6b8", + "contract_digest": "aaee4b8c2c21511270edf4281c2222eeccf2561cf9e6d6462ea0aac6aa26f379", + "workspace_digest": "b52f3e6f77eb34c8a94cc794482c0bede1f4fcb96711d4730ca5c9d4b7a8e9e5", + "acceptance_input_digest": "c83cef8c77ec1f7721f897ff4834eef8b98857db57cda000ab9d0ea6903bb9bb", "passed": true, "commands": [ { diff --git a/.specsync/change-sequence.json b/.specsync/change-sequence.json index 5857ddb..5ace796 100644 --- a/.specsync/change-sequence.json +++ b/.specsync/change-sequence.json @@ -1,6 +1,6 @@ { "schema_version": 1, - "sequence": 1, - "id": "CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts", + "sequence": 2, + "id": "CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review", "acknowledged_collisions": [] } diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/approvals.json b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/approvals.json new file mode 100644 index 0000000..c065872 --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/approvals.json @@ -0,0 +1,46 @@ +{ + "approvals": [ + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784396091, + "digest": "75056184138803c84d85114b485bbbc424c280e52b024d9840dc23f56ace7142", + "note": "Approve FileState watch cache and path isolation fixes from PR review." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784396094, + "digest": "13f79887f3aa6c765de95da8a27321fefdc3132474a4f8d91216673760c1a0b9", + "note": "Accept review fixes for watch note cross-process and path isolation." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784396148, + "digest": "75056184138803c84d85114b485bbbc424c280e52b024d9840dc23f56ace7142", + "note": "Re-approve CHG-0002 after evidence refresh." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784396151, + "digest": "2b6e60409c76df712a85a03938ec3d5108f9653a5c7b66ed0a65b8d98951819d", + "note": "Refresh CHG-0002 evidence under SpecSync 5.0.1." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784396248, + "digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "note": "Approve expanded full-PR path coverage with FileState review fixes." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784396251, + "digest": "d7d13c1e90666f773314a1536e8699b7010e5dab2d59bb16f6d6572da779e75f", + "note": "Accept review fixes as sole active SpecSync change." + } + ] +} diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/change.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/change.md new file mode 100644 index 0000000..7aa85f2 --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/change.md @@ -0,0 +1,25 @@ +--- +id: CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review +state: accepted +type: feature +base_commit: c6d9326fd7f4c7925deb5ff4f27f984a073bf6b8 +--- + +# Fix FileState watch cache and path isolation from review + +## Intent + +Fix FileState watch cache and path isolation from review + +## Affected Canonical Specs + +- `aps-cli` +- `state-store` + +## Acceptance Criteria + +- watch note sees cross-process file writes; StateStore preserves injected FileState paths; set note fails when disk write does not persist; specs/README match; 20 tests pass + +## No-spec Rationale + +Not applicable diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/context.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/context.md new file mode 100644 index 0000000..0cd21ca --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/context.md @@ -0,0 +1,16 @@ +--- +change: CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review +artifact: context +--- + +# Context + +PR review found that `watch note` could not see cross-process writes because +AppState FileState caches on first read. Also `StateStore.init` overwrote +test-injected FileState paths via `APSPaths.configure()`. + +## Decisions + +- Poll `note` by reading `note.json` directly (bypass AppState cache). +- Move `APSPaths.configure()` to CLI `boot()` only. +- After `set note`, verify on-disk value and throw `persistenceFailed` if mismatched. diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/deltas/aps-cli.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/deltas/aps-cli.md new file mode 100644 index 0000000..c266613 --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/deltas/aps-cli.md @@ -0,0 +1,43 @@ +# APS CLI FileState watch and error surface + +## MODIFIED + +### REQUIREMENT REQ-aps-cli-004 + +`watch` SHALL print the current value first and flush subsequent distinct values promptly, including cross-process `FileState` writes to `note`. + +Acceptance Criteria +- The first emitted line is the current value. +- Non-TTY stdout still surfaces each change without waiting for process exit. +- An external write to `note.json` is observed within one poll interval without relying on AppState's FileState cache. + +### REQUIREMENT REQ-aps-cli-005 + +`APSError` SHALL cover `unknownKey`, `invalidValue`, `encodingFailed`, `decodingFailed`, and `persistenceFailed`. + +Acceptance Criteria +- Each case has an actionable `description`. +- `set note` surfaces `persistenceFailed` when the on-disk value does not match after write. + +### SPEC SECTION Public API + +| Export | Description | +|--------|-------------| +| `DemoKey` | Fixed schema enum (`CaseIterable`, `ExpressibleByArgument`, `Sendable`). | +| `APSError` | Typed CLI/domain errors. | +| `counter` | Int key stored in AppState `State`. | +| `message` | String key stored in AppState `State`. | +| `flag` | Bool key stored in AppState `StoredState`. | +| `note` | String key stored in AppState `FileState`. | +| `unknownKey` | Unknown demo key token. | +| `invalidValue` | Value could not parse for the key type. | +| `encodingFailed` | UTF-8 JSON encode failure. | +| `decodingFailed` | UTF-8 JSON decode failure. | +| `persistenceFailed` | Disk-backed key did not persist after write. | +| `storage` | Human storage kind (`State` / `StoredState` / `FileState`). | +| `valueType` | Human value type (`Int` / `String` / `Bool`). | +| `helpSummary` | Tab-separated key/type/storage columns for `keys`. | +| `detail` | One-line description for `keys`. | +| `description` | Actionable error text for humans and ValidationError bridging. | + +Command tree (informational): `Aps` is the `@main` root (`ParsableCommand`) with get, set, watch, dump, keys, and reset / reset --all. CLI `boot()` calls `APSPaths.configure()`. diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/deltas/state-store.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/deltas/state-store.md new file mode 100644 index 0000000..3f31bff --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/deltas/state-store.md @@ -0,0 +1,53 @@ +# State Store FileState watch and path isolation + +## MODIFIED + +### REQUIREMENT REQ-state-store-001 + +`StateStore` SHALL read and write demo keys through AppState Application extensions on the main actor via `init`, `get`, and `set`, without overwriting an injected `FileManager.defaultFileStatePath`. + +Acceptance Criteria +- `get`/`set` round-trip `counter`, `message`, `flag`, and `note`. +- Mutating paths are MainActor-isolated. +- `init` loads dependencies only; CLI `boot()` (or tests) configure FileState paths. + +### REQUIREMENT REQ-state-store-003 + +Writing `flag` SHALL flush UserDefaults so Linux short-lived processes persist StoredState; writing `note` SHALL verify the on-disk value and throw `APSError.persistenceFailed` when persistence fails; `reset` / `resetAll` restore initials. + +Acceptance Criteria +- After `set(.flag, "true")`, a new `StateStore` instance observes true. +- After a successful `set(.note, ...)`, `readNoteFromDisk()` returns the same value. +- `reset(.flag)` restores false and flushes. + +### REQUIREMENT REQ-state-store-004 + +`watchBlocking` SHALL combine Observation with RunLoop polling and honor `shouldContinue`; for `note`, polling SHALL read the file directly so cross-process writes are visible despite AppState FileState caching; `parseBool` accepts common truthy/falsey tokens. + +Acceptance Criteria +- In-process `State` mutations are observed. +- External writes to `note.json` are observed without updating AppState's cache. +- `shouldContinue` false stops the loop without requiring Ctrl-C. + +### SPEC SECTION Public API + +| Export | Description | +|--------|-------------| +| `StateStore` | MainActor AppState facade used by the CLI. | +| `APSClock` | Clock protocol for dump timestamps. | +| `SystemAPSClock` | Production `APSClock` backed by `Date()`. | +| `JSONCoding` | Shared pretty JSON helpers. | +| `init` | Loads clock/jsonCoding dependencies without forcing `~/.aps`. | +| `get` | Return the string form of a demo key. | +| `set` | Parse and write; throw `APSError.invalidValue` or `persistenceFailed` on failure. | +| `reset` | Restore one key to its AppState initial value. | +| `resetAll` | Restore every demo key. | +| `dump` | Pretty JSON snapshot using `@AppDependency` clock + jsonCoding. | +| `watchBlocking` | Observation + RunLoop poll loop; `note` polls via direct disk read. | +| `parseBool` | Accept true/false/1/0/yes/no/on/off (case-insensitive). | +| `now` | Current `Date` from an `APSClock`. | +| `encodePretty` | Encode an `Encodable` value as pretty UTF-8 JSON text. | +| `decode` | Decode a `Decodable` value from UTF-8 JSON text. | +| `readNoteFromDisk` | Read `note.json` without touching AppState's FileState cache. | + +Application demo surface (informational): `Application.counter` / `message` / `flag` / `note` / `clock` / `jsonCoding`. `APSPaths.configure()` is invoked from CLI `boot()`, not `StateStore.init`. diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/design.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/design.md new file mode 100644 index 0000000..43f0e71 --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/design.md @@ -0,0 +1,12 @@ +--- +change: CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review +artifact: design +--- + +# Design + +Watch polling for `note` uses a direct JSON read of `note.json` under +`FileManager.defaultFileStatePath`, matching AppState's non-Base64 FileState +encoding. In-process `get`/`set` still go through AppState FileState so the +CLI continues to dogfood the library. Path configuration is a CLI boot concern +so tests can inject temp directories. diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/docs.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/docs.md new file mode 100644 index 0000000..a81fbdb --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/docs.md @@ -0,0 +1,9 @@ +--- +change: CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review +artifact: docs +--- + +# Docs + +README clarifies that `watch note` polls the file directly for cross-process +updates, and softens the untested Linux CI claim. diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/plan.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/plan.md new file mode 100644 index 0000000..c2a299c --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/plan.md @@ -0,0 +1,12 @@ +--- +change: CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review +artifact: plan +--- + +# Plan + +1. Add `freshValue` / `readNoteFromDisk` for watch polling of `note`. +2. Stop configuring FileState paths inside `StateStore.init`; call from `boot()`. +3. Verify note persistence after set; add `APSError.persistenceFailed`. +4. Add tests for external file writes and injected path isolation. +5. Update specs/README to match. diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/requirements.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/requirements.md new file mode 100644 index 0000000..3b158a0 --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/requirements.md @@ -0,0 +1,9 @@ +--- +change: CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review +artifact: requirements +--- + +# Requirements + +See semantic deltas for `REQ-aps-cli-004`, `REQ-aps-cli-005`, +`REQ-state-store-001`, `REQ-state-store-003`, and `REQ-state-store-004`. diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/state.json b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/state.json new file mode 100644 index 0000000..7a0454c --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/state.json @@ -0,0 +1,55 @@ +{ + "schema_version": 1, + "id": "CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review", + "slug": "fix-filestate-watch-cache-and-path-isolation-from-review", + "title": "Fix FileState watch cache and path isolation from review", + "description": "Fix FileState watch cache and path isolation from review", + "kind": "feature", + "state": "accepted", + "base_commit": "c6d9326fd7f4c7925deb5ff4f27f984a073bf6b8", + "created_at": 1784396041, + "updated_at": 1784396251, + "affected_specs": [ + "aps-cli", + "state-store" + ], + "affected_paths": [ + ".attest.json", + ".augur.toml", + ".github/workflows/", + ".gitignore", + ".specsync/", + ".trust.toml", + "AGENTS.md", + "CLAUDE.md", + "Package.resolved", + "Package.swift", + "README.md", + "Scripts/", + "Sources/", + "Tests/", + "fledge.toml", + "specs/" + ], + "no_spec_change": false, + "no_spec_change_rationale": null, + "acceptance_criteria": [ + "watch note sees cross-process file writes; StateStore preserves injected FileState paths; set note fails when disk write does not persist; specs/README match; 20 tests pass" + ], + "selected_artifacts": [ + "context", + "requirements", + "plan", + "tasks", + "testing", + "docs", + "design" + ], + "dependencies": [ + "CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts" + ], + "answers": { + "architecture_risk": "no", + "public_contract": "yes" + } +} diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/tasks.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/tasks.md new file mode 100644 index 0000000..8ffbef4 --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/tasks.md @@ -0,0 +1,12 @@ +--- +change: CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review +artifact: tasks +--- + +# Tasks + +- [x] Bypass FileState cache while polling `note` +- [x] Move `APSPaths.configure()` to CLI boot +- [x] Surface note persistence failures +- [x] Tests for external write watch + injected path +- [x] Spec/README updates diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/testing.md b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/testing.md new file mode 100644 index 0000000..0a6cd55 --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/testing.md @@ -0,0 +1,22 @@ +--- +change: CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review +artifact: testing +--- + +# Testing + +## Requirement evidence + +| Requirement | Evidence | +|-------------|----------| +| REQ-aps-cli-004 | `testWatchDetectsExternalFileStateWrite`, `testWatchDetectsFileStateChange` | +| REQ-aps-cli-005 | `testAPSErrorDescriptionsAreActionable` | +| REQ-state-store-001 | `testNoteUsesInjectedFileStatePath`, round-trip tests | +| REQ-state-store-003 | `testNoteFileStateRoundTrip`, `testFlagPersistsAcrossStateStoreInstances` | +| REQ-state-store-004 | `testWatchDetectsExternalFileStateWrite`, `testParseBool` | + +## Gate evidence + +- `swift test` (20 tests) +- `./Scripts/smoke.sh` +- `fledge lanes run verify` diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification.json b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification.json new file mode 100644 index 0000000..72d8e8f --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification.json @@ -0,0 +1,22 @@ +{ + "timestamp": 1784396251, + "commit": "c6d9326fd7f4c7925deb5ff4f27f984a073bf6b8", + "contract_digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "workspace_digest": "453dec7743a2e93811de583cf817d2ecdaf85a6ee3b315e5a4966dfe5eb2feec", + "acceptance_input_digest": "a0ecbb0b17e619708358399ba25760a9638101183e4eea783bd7c2d46cf56f48", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-003", + "REQ-state-store-004" + ] +} diff --git a/README.md b/README.md index fb1c645..4b25680 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A tiny Swift CLI that [dogfoods](https://github.com/0xLeif/AppState) **AppState** outside SwiftUI: declare typed app state, get/set/watch/dump it, and show dependency injection. -Cross-platform where AppState allows: **macOS** and **Linux** first. +Targets **macOS** (CI) and aims to stay Linux-friendly where AppState allows. This repository is gated by the [CorvidLabs trust toolchain](https://corvidlabs.xyz/integrate/) (fledge, spec-sync, augur, attest). See `AGENTS.md`. @@ -40,7 +40,7 @@ Dynamic / user-declared keys are intentionally out of scope for v1. ## Requirements - Swift 6.0+ -- macOS 14+ or Linux (Swift.org toolchain) +- macOS 14+ (CI). Linux toolchains are supported best-effort, not gated in CI yet. - For the trust gate locally: [corvid-trust](https://github.com/CorvidLabs/trust) (`brew install CorvidLabs/tap/corvid-trust`) ## Build and run @@ -77,7 +77,7 @@ swift run aps watch note --interval 200 swift run aps reset --all ``` -`watch` uses Swift Observation for in-process updates and polls as a fallback so disk-backed `FileState` / `StoredState` changes can still surface, including updates written by another `aps` process. +`watch` uses Swift Observation for in-process updates and polls as a fallback so disk-backed `FileState` / `StoredState` changes can still surface, including updates written by another `aps` process. For `note`, polling reads `note.json` directly so AppState's FileState cache cannot hide cross-process writes. ## Tests and smoke diff --git a/Sources/aps/Aps.swift b/Sources/aps/Aps.swift index f863f41..65f71d9 100644 --- a/Sources/aps/Aps.swift +++ b/Sources/aps/Aps.swift @@ -159,6 +159,7 @@ extension Aps { @MainActor private func boot() { Application.logging(isEnabled: false) + APSPaths.configure() } /// Synchronous `@main` starts on the real main thread; treat that as MainActor for AppState. diff --git a/Sources/aps/DemoKey.swift b/Sources/aps/DemoKey.swift index 18ec641..4939d98 100644 --- a/Sources/aps/DemoKey.swift +++ b/Sources/aps/DemoKey.swift @@ -48,6 +48,7 @@ public enum APSError: Error, CustomStringConvertible, Equatable { case invalidValue(key: DemoKey, value: String) case encodingFailed case decodingFailed + case persistenceFailed(key: DemoKey) public var description: String { switch self { @@ -59,6 +60,8 @@ public enum APSError: Error, CustomStringConvertible, Equatable { return "Failed to encode value as UTF-8 JSON" case .decodingFailed: return "Failed to decode value from UTF-8 JSON" + case .persistenceFailed(let key): + return "Failed to persist \(key.rawValue) to disk" } } } diff --git a/Sources/aps/DemoState.swift b/Sources/aps/DemoState.swift index 2ad0d7b..87fc7ee 100644 --- a/Sources/aps/DemoState.swift +++ b/Sources/aps/DemoState.swift @@ -42,6 +42,9 @@ extension Application { } /// Stable paths for CLI-persisted `FileState` data. +/// +/// Called from CLI `boot()` only. Tests inject their own +/// `FileManager.defaultFileStatePath` before constructing `StateStore`. enum APSPaths { @MainActor static var fileStateDirectory: String { diff --git a/Sources/aps/StateStore.swift b/Sources/aps/StateStore.swift index 3a1f135..a618361 100644 --- a/Sources/aps/StateStore.swift +++ b/Sources/aps/StateStore.swift @@ -6,13 +6,15 @@ import Observation /// /// Callers must be on the main thread: AppState asserts that in `notifyChange()`, /// and ArgumentParser's synchronous `@main` entry point provides that. +/// +/// FileState path configuration belongs to CLI `boot()` (or the test harness). +/// `StateStore` does not call `APSPaths.configure()`, so injected test paths stay put. @MainActor public final class StateStore { @AppDependency(\.clock) private var clock: any APSClock @AppDependency(\.jsonCoding) private var jsonCoding: JSONCoding public init() { - APSPaths.configure() Application.load(dependency: \.clock) Application.load(dependency: \.jsonCoding) } @@ -52,6 +54,12 @@ public final class StateStore { case .note: var state = Application.fileState(\.note) state.value = value + // AppState FileState swallows save errors after updating its cache. + // Confirm the value is actually on disk before claiming success. + let onDisk = try Self.readNoteFromDisk() + guard onDisk == value else { + throw APSError.persistenceFailed(key: .note) + } } } @@ -95,6 +103,8 @@ public final class StateStore { /// - Observation covers in-process mutations (`State`). /// - Polling re-reads values so `FileState` / `StoredState` updates can surface when /// Observation alone would not (e.g. another process wrote the file). + /// - For `note`, polling reads the file directly so AppState's FileState cache cannot + /// hide cross-process writes. /// - `shouldContinue` lets tests (and future tooling) stop the loop cleanly. public func watchBlocking( _ key: DemoKey, @@ -102,7 +112,7 @@ public final class StateStore { shouldContinue: () -> Bool = { true }, onChange: (String) -> Void ) { - var last = get(key) + var last = freshValue(key) onChange(last) let slice = max(pollInterval / 5.0, 0.05) @@ -118,7 +128,7 @@ public final class StateStore { while shouldContinue() { RunLoop.current.run(until: Date(timeIntervalSinceNow: slice)) - let current = get(key) + let current = freshValue(key) if flag.isSet || current != last { if current != last { last = current @@ -130,6 +140,30 @@ public final class StateStore { } } + /// Value used by watch polling. Disk-backed `note` bypasses AppState's FileState cache. + private func freshValue(_ key: DemoKey) -> String { + switch key { + case .note: + return (try? Self.readNoteFromDisk()) ?? get(key) + case .counter, .message, .flag: + return get(key) + } + } + + /// Read `note.json` without touching AppState's in-memory FileState cache. + /// + /// Mirrors AppState's non-Base64 FileState encoding: UTF-8 JSON via `JSONEncoder`. + public static func readNoteFromDisk() throws -> String { + let path = FileManager.defaultFileStatePath + let fileURL = URL(fileURLWithPath: path).appendingPathComponent("note.json") + do { + let data = try Data(contentsOf: fileURL) + return try JSONDecoder().decode(String.self, from: data) + } catch { + throw APSError.persistenceFailed(key: .note) + } + } + private func readForObservation(_ key: DemoKey) { switch key { case .counter: diff --git a/Tests/apsTests/APSTests.swift b/Tests/apsTests/APSTests.swift index f86c08a..2d3eb1b 100644 --- a/Tests/apsTests/APSTests.swift +++ b/Tests/apsTests/APSTests.swift @@ -173,6 +173,49 @@ final class APSTests: XCTestCase { XCTAssertEqual(seen, ["before", "after"]) } + @MainActor + func testWatchDetectsExternalFileStateWrite() async throws { + // Simulate another process: write note.json without updating AppState's cache. + let store = StateStore() + try store.set(.note, value: "before") + let path = FileManager.defaultFileStatePath + + var seen: [String] = [] + store.watchBlocking( + .note, + pollInterval: 0.05, + shouldContinue: { seen.count < 2 } + ) { value in + seen.append(value) + if value == "before" { + // Same on-disk format AppState uses for non-Base64 FileState. + let data = try? JSONEncoder().encode("changed") + let url = URL(fileURLWithPath: path).appendingPathComponent("note.json") + try? data?.write(to: url) + } + } + + XCTAssertEqual(seen, ["before", "changed"]) + } + + @MainActor + func testNoteUsesInjectedFileStatePath() async throws { + let path = FileManager.defaultFileStatePath + XCTAssertTrue(path.contains("aps-tests-"), "setUp must inject a temp FileState path") + + let store = StateStore() + try store.set(.note, value: "isolated") + + let fileURL = URL(fileURLWithPath: path).appendingPathComponent("note.json") + XCTAssertTrue(FileManager.default.fileExists(atPath: fileURL.path)) + + let homeNote = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent(".aps/note.json") + // Do not require ~/.aps to be absent globally; just ensure this write landed in temp. + XCTAssertNotEqual(fileURL.path, homeNote.path) + XCTAssertEqual(try StateStore.readNoteFromDisk(), "isolated") + } + @MainActor func testClockDependencyIsInjectable() async throws { let clock = Application.dependency(\.clock) @@ -239,5 +282,9 @@ final class APSTests: XCTestCase { let unknown = APSError.unknownKey("wat") XCTAssertTrue(unknown.description.contains("wat")) XCTAssertTrue(unknown.description.contains("counter")) + + let persistence = APSError.persistenceFailed(key: .note) + XCTAssertTrue(persistence.description.contains("note")) + XCTAssertTrue(persistence.description.contains("persist")) } } diff --git a/specs/aps-cli/aps-cli.spec.md b/specs/aps-cli/aps-cli.spec.md index 7b42df6..5529507 100644 --- a/specs/aps-cli/aps-cli.spec.md +++ b/specs/aps-cli/aps-cli.spec.md @@ -1,6 +1,6 @@ --- module: aps-cli -version: 4 +version: 8 status: active files: - Sources/aps/Aps.swift @@ -32,13 +32,14 @@ agents can get, set, watch, dump, list, and reset typed application state. | `invalidValue` | Value could not parse for the key type. | | `encodingFailed` | UTF-8 JSON encode failure. | | `decodingFailed` | UTF-8 JSON decode failure. | +| `persistenceFailed` | Disk-backed key did not persist after write. | | `storage` | Human storage kind (`State` / `StoredState` / `FileState`). | | `valueType` | Human value type (`Int` / `String` / `Bool`). | | `helpSummary` | Tab-separated key/type/storage columns for `keys`. | | `detail` | One-line description for `keys`. | | `description` | Actionable error text for humans and ValidationError bridging. | -Command tree (informational): `Aps` is the `@main` root (`ParsableCommand`) with get, set, watch, dump, keys, and reset / reset --all. +Command tree (informational): `Aps` is the `@main` root (`ParsableCommand`) with get, set, watch, dump, keys, and reset / reset --all. CLI `boot()` calls `APSPaths.configure()`. ## Invariants @@ -84,6 +85,7 @@ Then the watcher prints `changed` within one poll interval. - Non-boolean `flag` value: `APSError.invalidValue` -> ValidationError. - `reset` with neither a key nor `--all`: ValidationError. - `reset` with both a key and `--all`: ValidationError. +- Failed `note` disk persistence: `APSError.persistenceFailed` -> ValidationError. ## Dependencies @@ -97,3 +99,7 @@ Then the watcher prints `changed` within one poll interval. - 2: Explicit export inventory for SpecSync active-contract checks (`DemoKey`, `APSError`). | 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | | 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | +| 2026-07-18 | CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review: Fix FileState watch cache and path isolation from review | +| 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | +| 2026-07-18 | CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review: Fix FileState watch cache and path isolation from review | +| 2026-07-18 | CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review: Fix FileState watch cache and path isolation from review | diff --git a/specs/aps-cli/requirements.md b/specs/aps-cli/requirements.md index 6ddc286..a618710 100644 --- a/specs/aps-cli/requirements.md +++ b/specs/aps-cli/requirements.md @@ -33,17 +33,18 @@ Acceptance Criteria ### REQ-aps-cli-004 -`watch` SHALL print the current value first and flush subsequent distinct values promptly. +`watch` SHALL print the current value first and flush subsequent distinct values promptly, including cross-process `FileState` writes to `note`. Acceptance Criteria - The first emitted line is the current value. - Non-TTY stdout still surfaces each change without waiting for process exit. +- An external write to `note.json` is observed within one poll interval without relying on AppState's FileState cache. ### REQ-aps-cli-005 -`APSError` SHALL cover `unknownKey`, `invalidValue`, `encodingFailed`, and `decodingFailed`. +`APSError` SHALL cover `unknownKey`, `invalidValue`, `encodingFailed`, `decodingFailed`, and `persistenceFailed`. Acceptance Criteria -- Each case is reachable from CLI or StateStore coding paths. -- `description` is suitable for ValidationError bridging. +- Each case has an actionable `description`. +- `set note` surfaces `persistenceFailed` when the on-disk value does not match after write. diff --git a/specs/state-store/requirements.md b/specs/state-store/requirements.md index a56d128..cf856a4 100644 --- a/specs/state-store/requirements.md +++ b/specs/state-store/requirements.md @@ -8,11 +8,12 @@ spec: state-store.spec.md ### REQ-state-store-001 -`StateStore` SHALL read and write demo keys through AppState Application extensions on the main actor via `init`, `get`, and `set`. +`StateStore` SHALL read and write demo keys through AppState Application extensions on the main actor via `init`, `get`, and `set`, without overwriting an injected `FileManager.defaultFileStatePath`. Acceptance Criteria - `get`/`set` round-trip `counter`, `message`, `flag`, and `note`. - Mutating paths are MainActor-isolated. +- `init` loads dependencies only; CLI `boot()` (or tests) configure FileState paths. ### REQ-state-store-002 @@ -24,18 +25,19 @@ Acceptance Criteria ### REQ-state-store-003 -Writing `flag` SHALL flush UserDefaults so Linux short-lived processes persist StoredState; `reset` / `resetAll` restore initials. +Writing `flag` SHALL flush UserDefaults so Linux short-lived processes persist StoredState; writing `note` SHALL verify the on-disk value and throw `APSError.persistenceFailed` when persistence fails; `reset` / `resetAll` restore initials. Acceptance Criteria - After `set(.flag, "true")`, a new `StateStore` instance observes true. +- After a successful `set(.note, ...)`, `readNoteFromDisk()` returns the same value. - `reset(.flag)` restores false and flushes. ### REQ-state-store-004 -`watchBlocking` SHALL combine Observation with RunLoop polling and honor `shouldContinue`; `parseBool` accepts common truthy/falsey tokens. +`watchBlocking` SHALL combine Observation with RunLoop polling and honor `shouldContinue`; for `note`, polling SHALL read the file directly so cross-process writes are visible despite AppState FileState caching; `parseBool` accepts common truthy/falsey tokens. Acceptance Criteria - In-process `State` mutations are observed. -- `FileState` mutations performed during the loop are observed. +- External writes to `note.json` are observed without updating AppState's cache. - `shouldContinue` false stops the loop without requiring Ctrl-C. diff --git a/specs/state-store/state-store.spec.md b/specs/state-store/state-store.spec.md index 2dc56e3..1de7a04 100644 --- a/specs/state-store/state-store.spec.md +++ b/specs/state-store/state-store.spec.md @@ -1,6 +1,6 @@ --- module: state-store -version: 4 +version: 8 status: active files: - Sources/aps/StateStore.swift @@ -27,19 +27,20 @@ non-UI use. | `APSClock` | Clock protocol for dump timestamps. | | `SystemAPSClock` | Production `APSClock` backed by `Date()`. | | `JSONCoding` | Shared pretty JSON helpers. | -| `init` | Configures FileState path and loads clock/jsonCoding dependencies. | +| `init` | Loads clock/jsonCoding dependencies without forcing `~/.aps`. | | `get` | Return the string form of a demo key. | -| `set` | Parse and write; throw `APSError.invalidValue` on bad input. | +| `set` | Parse and write; throw `APSError.invalidValue` or `persistenceFailed` on failure. | | `reset` | Restore one key to its AppState initial value. | | `resetAll` | Restore every demo key. | | `dump` | Pretty JSON snapshot using `@AppDependency` clock + jsonCoding. | -| `watchBlocking` | Observation + RunLoop poll loop with `shouldContinue`. | +| `watchBlocking` | Observation + RunLoop poll loop; `note` polls via direct disk read. | | `parseBool` | Accept true/false/1/0/yes/no/on/off (case-insensitive). | | `now` | Current `Date` from an `APSClock`. | | `encodePretty` | Encode an `Encodable` value as pretty UTF-8 JSON text. | | `decode` | Decode a `Decodable` value from UTF-8 JSON text. | +| `readNoteFromDisk` | Read `note.json` without touching AppState's FileState cache. | -Application demo surface (informational): `Application.counter` / `message` / `flag` / `note` / `clock` / `jsonCoding`, with `APSPaths.configure()` pointing FileState at `~/.aps`. +Application demo surface (informational): `Application.counter` / `message` / `flag` / `note` / `clock` / `jsonCoding`. `APSPaths.configure()` is invoked from CLI `boot()`, not `StateStore.init`. ## Invariants @@ -95,3 +96,7 @@ Then keys include message with value "hi" and a timestamp field exists. - 2: Explicit export inventory for SpecSync active-contract checks. | 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | | 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | +| 2026-07-18 | CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review: Fix FileState watch cache and path isolation from review | +| 2026-07-18 | CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts: Adopt CorvidLabs trust and establish aps module contracts | +| 2026-07-18 | CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review: Fix FileState watch cache and path isolation from review | +| 2026-07-18 | CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review: Fix FileState watch cache and path isolation from review | From 458f017c10e6f7a7ad295403cf82bc4d3d829fe4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 18 Jul 2026 17:54:11 +0000 Subject: [PATCH 9/9] Upgrade SpecSync pin and Trust CI to 5.1.1 Remove the incomplete 5.0.1 manual archive that lacked legacy-baseline.json, rebind CHG-0002 under SpecSync 5.1.1, and wire Trust v1.0.1 with a runner-temp file:// mirror so local brew SpecSync and CI share the same tool version. Co-authored-by: Leif --- .github/workflows/trust.yml | 28 +- .../approvals.json | 123 --- .../change.md | 25 - .../context.md | 8 - .../deltas/aps-cli.md | 68 -- .../deltas/state-store.md | 61 -- .../design.md | 12 - .../docs.md | 8 - .../plan.md | 12 - .../requirements.md | 8 - .../research.md | 8 - .../state.json | 54 -- .../tasks.md | 13 - .../testing.md | 26 - .../verification-attempts.json | 130 --- .../verification.json | 26 - .../approvals.json | 881 ++++++++++++++++++ .../state.json | 3 +- .../verification-attempts.json | 89 ++ .../verification.json | 363 +++++++- .specsync/version | 2 +- README.md | 3 +- 22 files changed, 1360 insertions(+), 591 deletions(-) delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json delete mode 100644 .specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json create mode 100644 .specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification-attempts.json diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml index 027c014..894c909 100644 --- a/.github/workflows/trust.yml +++ b/.github/workflows/trust.yml @@ -1,7 +1,8 @@ name: Trust # Private repo: CorvidLabs trust gate on macOS self-hosted runners. -# SpecSync acceptance evidence rebound with the Trust-pinned 5.0.1 CLI. +# SpecSync pin is 5.1.1 via Trust v1.0.1 + a runner-temp file:// mirror +# (non-default SpecSync versions cannot use the remote GitHub download path). # Revisit before making the repository public: fork PRs must not run on # self-hosted hosts. @@ -41,11 +42,34 @@ jobs: echo "range=${{ github.event.before }}..${{ github.sha }}" >> "$GITHUB_OUTPUT" fi + # Trust rejects remote download overrides for non-default SpecSync versions. + # Stage the 5.1.1 release archives under RUNNER_TEMP for an authority-free + # file:// mirror (platform archive + adjacent .sha256). + - name: Prepare SpecSync 5.1.1 local mirror + id: specsync_mirror + run: | + set -euo pipefail + VERSION="5.1.1" + MIRROR="${RUNNER_TEMP}/specsync-${VERSION}-mirror" + mkdir -p "$MIRROR" + BASE="https://github.com/CorvidLabs/spec-sync/releases/download/v${VERSION}" + for asset in \ + specsync-macos-aarch64.tar.gz \ + specsync-macos-x86_64.tar.gz + do + curl -fsSL "${BASE}/${asset}" -o "${MIRROR}/${asset}" + curl -fsSL "${BASE}/${asset}.sha256" -o "${MIRROR}/${asset}.sha256" + (cd "$MIRROR" && shasum -a 256 -c "${asset}.sha256") + done + echo "path=${MIRROR}" >> "$GITHUB_OUTPUT" + - name: CorvidLabs Trust gate id: trust - uses: CorvidLabs/trust@9d32b5786d2e9e4d39fc581c0091c721ee3d4226 # v1.0.0 + uses: CorvidLabs/trust@c8f969a12209575877b5eca1ec557431621381e0 # v1.0.1 with: range: ${{ steps.trust_range.outputs.range }} + specsync-version: "5.1.1" + specsync-download-base-url: file://${{ steps.specsync_mirror.outputs.path }} - name: Check managed agent rules run: | diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json deleted file mode 100644 index c042cc7..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/approvals.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "approvals": [ - { - "gate": "definition", - "actor": "agent:cursor", - "timestamp": 1784393175, - "digest": "3155ae53d2f499b09d1c15b5bfde985844e4e0c4269a452b53e6330920594fb0", - "note": "Approved trust adoption with aps-cli/state-store semantic contracts." - }, - { - "gate": "definition", - "actor": "agent:cursor", - "timestamp": 1784393218, - "digest": "1117f027d5039903b7f17872c7749aaca939df950c2cb801db99adc668e56415", - "note": "Re-approved after export-safe deltas and requirement evidence." - }, - { - "gate": "definition", - "actor": "agent:cursor", - "timestamp": 1784393224, - "digest": "1117f027d5039903b7f17872c7749aaca939df950c2cb801db99adc668e56415", - "note": "Approved with full Public API section in deltas." - }, - { - "gate": "definition", - "actor": "leif algo", - "timestamp": 1784393345, - "digest": "6006090dbf5b7d599955e51ef4fd75cf35e4b36fb1f513efb311aa8439dc7cba", - "note": "Continue without waiting for self-hosted runners; approve refreshed export-documented deltas." - }, - { - "gate": "definition", - "actor": "leif algo", - "timestamp": 1784393364, - "digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "note": "Re-approve after switching existing REQs to MODIFIED; ADDED only REQ-aps-cli-005." - }, - { - "gate": "acceptance", - "actor": "leif algo", - "timestamp": 1784393368, - "digest": "6d19a3078f062938ee3e14692d1ed6694ceb70bdc794146a86108cc8c1de509b", - "note": "Accept after local verify green; CI awaits macOS self-hosted runners." - }, - { - "gate": "definition", - "actor": "leif algo", - "timestamp": 1784393403, - "digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "note": "Re-approve after reopen for companion finalization." - }, - { - "gate": "acceptance", - "actor": "leif algo", - "timestamp": 1784393407, - "digest": "4145e1bdd5239a9d33b52c4208171b5d98be0b5ecc5e1d1e28451194cb689de8", - "note": "Re-accept with current companions and export tables." - }, - { - "gate": "definition", - "actor": "leif algo", - "timestamp": 1784394701, - "digest": "cc9272eb0555774991e025749c04256dc796539787c1ae0b118f5f94c008163e", - "note": "Approve Trust workflow range fix for self-hosted CI." - }, - { - "gate": "definition", - "actor": "leif algo", - "timestamp": 1784394711, - "digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "note": "Re-approve unchanged definition after Trust workflow delivery fix." - }, - { - "gate": "acceptance", - "actor": "leif algo", - "timestamp": 1784394715, - "digest": "bf47283138ee6da7f4434e6ff1ca9b7d34db666ea784474b36b45eec525f2ccc", - "note": "Re-accept with Trust range workflow delivery fix." - }, - { - "gate": "definition", - "actor": "leif algo", - "timestamp": 1784394921, - "digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "note": "Approve unchanged definition before 5.0.1 evidence rebind." - }, - { - "gate": "definition", - "actor": "leif algo", - "timestamp": 1784394931, - "digest": "6c81bf7ec50ac551292c3a5ade4785a61736c5b608ff255d0e14e8a24c3f619f", - "note": "Approve delta fix: REQ-aps-cli-005 is MODIFIED on re-accept." - }, - { - "gate": "acceptance", - "actor": "leif algo", - "timestamp": 1784394935, - "digest": "ab2e8e65c3b94ebfde36bcafe2bab2d40be3020b702c363ef38dbb218c355f1e", - "note": "Accept with SpecSync 5.0.1 digests matching Trust CI." - }, - { - "gate": "definition", - "actor": "leif algo", - "timestamp": 1784396118, - "digest": "6c81bf7ec50ac551292c3a5ade4785a61736c5b608ff255d0e14e8a24c3f619f", - "note": "Re-approve unchanged CHG-0001 definition for evidence refresh." - }, - { - "gate": "definition", - "actor": "leif algo", - "timestamp": 1784396140, - "digest": "aaee4b8c2c21511270edf4281c2222eeccf2561cf9e6d6462ea0aac6aa26f379", - "note": "Align CHG-0001 deltas with CHG-0002 FileState watch fixes for effective-contract verify." - }, - { - "gate": "acceptance", - "actor": "leif algo", - "timestamp": 1784396144, - "digest": "769752daa1b9594322e9303509eae744ffdcefdff2ff4d8eabc84b897477a59f", - "note": "Accept refreshed CHG-0001 evidence with current FileState contracts." - } - ] -} diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md deleted file mode 100644 index 2a2252c..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/change.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -id: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts -state: accepted -type: migration -base_commit: f4bd6f9adbc83a4ebaa8760a08f1f699566638f9 ---- - -# Adopt CorvidLabs trust and establish aps module contracts - -## Intent - -Adopt CorvidLabs trust and establish aps module contracts - -## Affected Canonical Specs - -- `aps-cli` -- `state-store` - -## Acceptance Criteria - -- Trust config and self-hosted macOS CI are committed; aps-cli and state-store active contracts pass specsync check; fledge verify lane builds tests and smokes; targeted unit tests cover reset/keys validation and flag persistence - -## No-spec Rationale - -Not applicable diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md deleted file mode 100644 index 19c0a95..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/context.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts -artifact: context ---- - -# Context - -aps-cli dogfoods AppState as a Swift CLI. This migration adopts the CorvidLabs trust toolchain, establishes canonical module contracts, and keeps CI on macOS self-hosted runners while the repository is private. diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md deleted file mode 100644 index 9ff2d8a..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/aps-cli.md +++ /dev/null @@ -1,68 +0,0 @@ -# APS CLI contract introduction - -## MODIFIED - -### REQUIREMENT REQ-aps-cli-005 - -`APSError` SHALL cover `unknownKey`, `invalidValue`, `encodingFailed`, `decodingFailed`, and `persistenceFailed`. - -Acceptance Criteria -- Each case has an actionable `description`. -- `set note` surfaces `persistenceFailed` when the on-disk value does not match after write. - -### REQUIREMENT REQ-aps-cli-001 - -The CLI SHALL expose get, set, watch, dump, keys, and reset over the fixed `DemoKey` schema covering `counter`, `message`, `flag`, and `note`. - -Acceptance Criteria -- `aps --help` lists those subcommands. -- `DemoKey` includes only those four cases and exposes `storage`, `valueType`, `helpSummary`, and `detail`. - -### REQUIREMENT REQ-aps-cli-002 - -`set` SHALL reject values that cannot parse to the key's type and exit non-zero via `APSError.invalidValue`. - -Acceptance Criteria -- Non-integer `counter` values fail with an invalid-value message. -- Non-boolean `flag` values fail with an invalid-value message. -- `APSError.description` names the key and expected type. - -### REQUIREMENT REQ-aps-cli-003 - -Process-local `State` keys SHALL not be required to persist across process boundaries. - -Acceptance Criteria -- `counter` and `message` are documented and tested as process-local. -- `flag` (`StoredState`) and `note` (`FileState`) persist across processes after a successful set. - -### REQUIREMENT REQ-aps-cli-004 - -`watch` SHALL print the current value first and flush subsequent distinct values promptly, including cross-process `FileState` writes to `note`. - -Acceptance Criteria -- The first emitted line is the current value. -- Non-TTY stdout still surfaces each change without waiting for process exit. -- An external write to `note.json` is observed within one poll interval without relying on AppState's FileState cache. - -### SPEC SECTION Public API - -| Export | Description | -|--------|-------------| -| `DemoKey` | Fixed schema enum (`CaseIterable`, `ExpressibleByArgument`, `Sendable`). | -| `APSError` | Typed CLI/domain errors. | -| `counter` | Int key stored in AppState `State`. | -| `message` | String key stored in AppState `State`. | -| `flag` | Bool key stored in AppState `StoredState`. | -| `note` | String key stored in AppState `FileState`. | -| `unknownKey` | Unknown demo key token. | -| `invalidValue` | Value could not parse for the key type. | -| `encodingFailed` | UTF-8 JSON encode failure. | -| `decodingFailed` | UTF-8 JSON decode failure. | -| `persistenceFailed` | Disk-backed key did not persist after write. | -| `storage` | Human storage kind (`State` / `StoredState` / `FileState`). | -| `valueType` | Human value type (`Int` / `String` / `Bool`). | -| `helpSummary` | Tab-separated key/type/storage columns for `keys`. | -| `detail` | One-line description for `keys`. | -| `description` | Actionable error text for humans and ValidationError bridging. | - -Command tree (informational): `Aps` is the `@main` root (`ParsableCommand`) with get, set, watch, dump, keys, and reset / reset --all. CLI `boot()` calls `APSPaths.configure()`. diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md deleted file mode 100644 index 1690c98..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/deltas/state-store.md +++ /dev/null @@ -1,61 +0,0 @@ -# State Store contract introduction - -## MODIFIED - -### REQUIREMENT REQ-state-store-001 - -`StateStore` SHALL read and write demo keys through AppState Application extensions on the main actor via `init`, `get`, and `set`, without overwriting an injected `FileManager.defaultFileStatePath`. - -Acceptance Criteria -- `get`/`set` round-trip `counter`, `message`, `flag`, and `note`. -- Mutating paths are MainActor-isolated. -- `init` loads dependencies only; CLI `boot()` (or tests) configure FileState paths. - -### REQUIREMENT REQ-state-store-002 - -`StateStore` SHALL inject real `APSClock` / `SystemAPSClock` (`now`) and `JSONCoding` (`encodePretty`, `decode`) dependencies for `dump` output. - -Acceptance Criteria -- `dump` JSON includes every `DemoKey` and a timestamp. -- Dependencies are loaded via `Application.dependency` / `@AppDependency`. - -### REQUIREMENT REQ-state-store-003 - -Writing `flag` SHALL flush UserDefaults so Linux short-lived processes persist StoredState; writing `note` SHALL verify the on-disk value and throw `APSError.persistenceFailed` when persistence fails; `reset` / `resetAll` restore initials. - -Acceptance Criteria -- After `set(.flag, "true")`, a new `StateStore` instance observes true. -- After a successful `set(.note, ...)`, `readNoteFromDisk()` returns the same value. -- `reset(.flag)` restores false and flushes. - -### REQUIREMENT REQ-state-store-004 - -`watchBlocking` SHALL combine Observation with RunLoop polling and honor `shouldContinue`; for `note`, polling SHALL read the file directly so cross-process writes are visible despite AppState FileState caching; `parseBool` accepts common truthy/falsey tokens. - -Acceptance Criteria -- In-process `State` mutations are observed. -- External writes to `note.json` are observed without updating AppState's cache. -- `shouldContinue` false stops the loop without requiring Ctrl-C. - -### SPEC SECTION Public API - -| Export | Description | -|--------|-------------| -| `StateStore` | MainActor AppState facade used by the CLI. | -| `APSClock` | Clock protocol for dump timestamps. | -| `SystemAPSClock` | Production `APSClock` backed by `Date()`. | -| `JSONCoding` | Shared pretty JSON helpers. | -| `init` | Loads clock/jsonCoding dependencies without forcing `~/.aps`. | -| `get` | Return the string form of a demo key. | -| `set` | Parse and write; throw `APSError.invalidValue` or `persistenceFailed` on failure. | -| `reset` | Restore one key to its AppState initial value. | -| `resetAll` | Restore every demo key. | -| `dump` | Pretty JSON snapshot using `@AppDependency` clock + jsonCoding. | -| `watchBlocking` | Observation + RunLoop poll loop; `note` polls via direct disk read. | -| `parseBool` | Accept true/false/1/0/yes/no/on/off (case-insensitive). | -| `now` | Current `Date` from an `APSClock`. | -| `encodePretty` | Encode an `Encodable` value as pretty UTF-8 JSON text. | -| `decode` | Decode a `Decodable` value from UTF-8 JSON text. | -| `readNoteFromDisk` | Read `note.json` without touching AppState's FileState cache. | - -Application demo surface (informational): `Application.counter` / `message` / `flag` / `note` / `clock` / `jsonCoding`. `APSPaths.configure()` is invoked from CLI `boot()`, not `StateStore.init`. diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md deleted file mode 100644 index b35b1e2..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/design.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts -artifact: design ---- - -# Design - -- Standard Trust profile with soft provenance -- Canonical specs: aps-cli (CLI surface) and state-store (AppState access) -- Semantic deltas introduce stable REQ-IDs for each public behavior -- fledge verify: build, test, smoke, and specsync check -- CI/Trust workflows: runs-on [self-hosted, macOS] diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md deleted file mode 100644 index 844c90c..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/docs.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts -artifact: docs ---- - -# Docs - -README documents commands, trust files, and the private-repo self-hosted runner policy. AGENTS.md carries the managed CorvidLabs trust toolchain block. Module contracts live under specs/. diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md deleted file mode 100644 index 4220a38..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/plan.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts -artifact: plan ---- - -# Plan - -1. Commit trust/spec-sync/augur/attest config and AGENTS.md markers -2. Author and activate aps-cli and state-store specs with companions -3. Apply semantic deltas establishing ownership REQ-IDs -4. Expand targeted tests and add spec to the fledge verify lane -5. Verify, accept, and archive this change; record attest provenance diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md deleted file mode 100644 index a1cb4dc..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/requirements.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts -artifact: requirements ---- - -# Requirements - -See semantic deltas under deltas/ for REQ-aps-cli-* and REQ-state-store-* introductions applied on acceptance. diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md deleted file mode 100644 index 31a0896..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/research.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts -artifact: research ---- - -# Research - -Trust 1 composes fledge, SpecSync 5, augur, and attest. SpecSync acceptance requires production sources to have deterministic canonical ownership through affected specs and semantic deltas. Self-hosted macOS runners are preferred while private; hosted runners succeeded earlier for Linux/macOS smoke. diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json deleted file mode 100644 index 414a5df..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/state.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "schema_version": 1, - "id": "CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts", - "slug": "adopt-corvidlabs-trust-and-establish-aps-module-contracts", - "title": "Adopt CorvidLabs trust and establish aps module contracts", - "description": "Adopt CorvidLabs trust and establish aps module contracts", - "kind": "migration", - "state": "archived", - "base_commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", - "created_at": 1784393134, - "updated_at": 1784396144, - "affected_specs": [ - "aps-cli", - "state-store" - ], - "affected_paths": [ - ".github/workflows/", - ".specsync/", - "specs/", - "Sources/", - "Tests/", - "Scripts/", - "fledge.toml", - ".trust.toml", - ".augur.toml", - ".attest.json", - "AGENTS.md", - "CLAUDE.md", - "README.md", - "Package.swift", - "Package.resolved", - ".gitignore" - ], - "no_spec_change": false, - "no_spec_change_rationale": null, - "acceptance_criteria": [ - "Trust config and self-hosted macOS CI are committed; aps-cli and state-store active contracts pass specsync check; fledge verify lane builds tests and smokes; targeted unit tests cover reset/keys validation and flag persistence" - ], - "selected_artifacts": [ - "context", - "research", - "design", - "plan", - "tasks", - "testing", - "docs", - "requirements" - ], - "dependencies": [], - "answers": { - "architecture_risk": "no", - "public_contract": "yes" - } -} diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md deleted file mode 100644 index c0b899b..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/tasks.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts -artifact: tasks ---- - -# Tasks - -- [x] Trust config, AGENTS.md, self-hosted macOS CI/Trust workflows -- [x] SpecSync policy, registry, and active module specs -- [x] Semantic deltas for aps-cli and state-store -- [x] Targeted unit tests (reset/keys validation, flag persistence) -- [x] Keep verify lane native-only; expose `fledge run check` with specsync -- [x] Local verify evidence recorded for acceptance diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md deleted file mode 100644 index 27ff6cc..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/testing.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -change: CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts -artifact: testing ---- - -# Testing - -## Requirement evidence - -| Requirement | Evidence | -|-------------|----------| -| REQ-aps-cli-001 | `testDemoKeyMetadata`, `testDemoKeyHelpSummaryFormat`, `Scripts/smoke.sh` keys | -| REQ-aps-cli-002 | `testInvalidCounterValue`, `testInvalidFlagValue`, `testAPSErrorDescriptionsAreActionable` | -| REQ-aps-cli-003 | `testProcessLocalStateKeysDoNotClaimCrossProcessPersistence`, `testFlagPersistsAcrossStateStoreInstances`, smoke flag/note | -| REQ-aps-cli-004 | `testWatchDetectsInProcessStateChange`, `testWatchDetectsFileStateChange`, `testWatchDetectsExternalFileStateWrite` | -| REQ-aps-cli-005 | `testAPSErrorDescriptionsAreActionable`, `testInvalidCounterValue` | -| REQ-state-store-001 | `testCounterRoundTrip`, `testMessageAndFlagRoundTrip`, `testNoteFileStateRoundTrip` | -| REQ-state-store-002 | `testDumpIncludesKeysAndUsesDependency`, `testJSONCodingDependency`, `testClockDependencyIsInjectable` | -| REQ-state-store-003 | `testFlagPersistsAcrossStateStoreInstances`, `testResetRestoresInitialValues`, `testResetAll` | -| REQ-state-store-004 | `testWatchDetectsInProcessStateChange`, `testWatchDetectsExternalFileStateWrite`, `testParseBool` | - -## Gate evidence - -- `swift test` (20 tests) -- `./Scripts/smoke.sh` -- `fledge lanes run verify` diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json deleted file mode 100644 index b5b2f1f..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification-attempts.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "schema_version": 1, - "attempts": [ - { - "timestamp": 1784393349, - "commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", - "contract_digest": "6006090dbf5b7d599955e51ef4fd75cf35e4b36fb1f513efb311aa8439dc7cba", - "workspace_digest": "c8511495beb59a1886f889207c2367c0cad3fa3efcba98a29d28ef1a1c5ddcd0", - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-aps-cli-001", - "REQ-aps-cli-002", - "REQ-aps-cli-003", - "REQ-aps-cli-004", - "REQ-aps-cli-005", - "REQ-state-store-001", - "REQ-state-store-002", - "REQ-state-store-003", - "REQ-state-store-004" - ] - }, - { - "timestamp": 1784393368, - "commit": "f4bd6f9adbc83a4ebaa8760a08f1f699566638f9", - "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "workspace_digest": "c8511495beb59a1886f889207c2367c0cad3fa3efcba98a29d28ef1a1c5ddcd0", - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-aps-cli-001", - "REQ-aps-cli-002", - "REQ-aps-cli-003", - "REQ-aps-cli-004", - "REQ-aps-cli-005", - "REQ-state-store-001", - "REQ-state-store-002", - "REQ-state-store-003", - "REQ-state-store-004" - ] - }, - { - "timestamp": 1784393406, - "commit": "d5f28efeb86135279b7a5ba8bed8894a2c290a35", - "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "workspace_digest": "617795e00f0d67a61a7059e8e4cd218dc16e0dd45f517e3bedbf55c83312d7fa", - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-aps-cli-001", - "REQ-aps-cli-002", - "REQ-aps-cli-003", - "REQ-aps-cli-004", - "REQ-aps-cli-005", - "REQ-state-store-001", - "REQ-state-store-002", - "REQ-state-store-003", - "REQ-state-store-004" - ] - }, - { - "timestamp": 1784394704, - "commit": "fbcb4636cc4a05c7c21da5342042ec9d541d90db", - "contract_digest": "cc9272eb0555774991e025749c04256dc796539787c1ae0b118f5f94c008163e", - "workspace_digest": "d89692495b79a09750d340fdf0f552ef89651a3e7b75a409d9adf4890456cef2", - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-aps-cli-001", - "REQ-aps-cli-002", - "REQ-aps-cli-003", - "REQ-aps-cli-004", - "REQ-aps-cli-005", - "REQ-state-store-001", - "REQ-state-store-002", - "REQ-state-store-003", - "REQ-state-store-004" - ] - }, - { - "timestamp": 1784394714, - "commit": "fbcb4636cc4a05c7c21da5342042ec9d541d90db", - "contract_digest": "003a14da3aa73cf99683a59b58513e52661985fbcf4f754cc48e8cc39631952c", - "workspace_digest": "d89692495b79a09750d340fdf0f552ef89651a3e7b75a409d9adf4890456cef2", - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-aps-cli-001", - "REQ-aps-cli-002", - "REQ-aps-cli-003", - "REQ-aps-cli-004", - "REQ-aps-cli-005", - "REQ-state-store-001", - "REQ-state-store-002", - "REQ-state-store-003", - "REQ-state-store-004" - ] - } - ] -} diff --git a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json b/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json deleted file mode 100644 index affdcaf..0000000 --- a/.specsync/archive/changes/2026-07-18-CHG-0001-adopt-corvidlabs-trust-and-establish-aps-module-contracts/verification.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "timestamp": 1784396144, - "commit": "c6d9326fd7f4c7925deb5ff4f27f984a073bf6b8", - "contract_digest": "aaee4b8c2c21511270edf4281c2222eeccf2561cf9e6d6462ea0aac6aa26f379", - "workspace_digest": "b52f3e6f77eb34c8a94cc794482c0bede1f4fcb96711d4730ca5c9d4b7a8e9e5", - "acceptance_input_digest": "c83cef8c77ec1f7721f897ff4834eef8b98857db57cda000ab9d0ea6903bb9bb", - "passed": true, - "commands": [ - { - "command": "fledge lanes run verify", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-aps-cli-001", - "REQ-aps-cli-002", - "REQ-aps-cli-003", - "REQ-aps-cli-004", - "REQ-aps-cli-005", - "REQ-state-store-001", - "REQ-state-store-002", - "REQ-state-store-003", - "REQ-state-store-004" - ] -} diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/approvals.json b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/approvals.json index c065872..4478639 100644 --- a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/approvals.json +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/approvals.json @@ -41,6 +41,887 @@ "timestamp": 1784396251, "digest": "d7d13c1e90666f773314a1536e8699b7010e5dab2d59bb16f6d6572da779e75f", "note": "Accept review fixes as sole active SpecSync change." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784397142, + "digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "note": "Re-approve after SpecSync 5.1.1 pin; no semantic contract definition change." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784397150, + "digest": "bbc61826d284f74a887be499160214984e401f31a7fb1d78ea2464201cad270c", + "note": "Accepted under SpecSync 5.1.1; incomplete 5.0.1 manual archive removed." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784397197, + "digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "note": "Re-approve after Trust v1.0.1 + SpecSync 5.1.1 mirror wiring; no semantic contract definition change." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784397204, + "digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "note": "Re-approve after Trust v1.0.1 + SpecSync 5.1.1 mirror wiring; no semantic contract definition change." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784397208, + "digest": "2a023c4ceb638ee95b162ef18367cb5338e75124bee1a189fbc6aab47e30bdd0", + "note": "Accepted SpecSync 5.1.1 project pin with Trust v1.0.1 CI mirror; incomplete 5.0.1 manual archive removed." + }, + { + "gate": "definition", + "actor": "leif algo", + "timestamp": 1784397241, + "digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "note": "Re-approve after README SpecSync 5.1.1 note; no semantic contract definition change." + }, + { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784397245, + "digest": "c19af25e22655b87941f13b433d7678274684e8ac449beb22277aee2c5702224", + "note": "Accepted with SpecSync 5.1.1 documented for local brew parity." + } + ], + "reopenings": [ + { + "schema_version": 1, + "change_id": "CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review", + "actor": "leif algo", + "reason": "Bump project SpecSync pin to 5.1.1 after removing incomplete 5.0.1 manual archive that lacked legacy-baseline.json; rebind evidence under latest SpecSync.", + "timestamp": 1784397141, + "from_state": "accepted", + "to_state": "verifying", + "superseded_approval": { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784396251, + "digest": "d7d13c1e90666f773314a1536e8699b7010e5dab2d59bb16f6d6572da779e75f", + "note": "Accept review fixes as sole active SpecSync change." + }, + "prior_verification": { + "timestamp": 1784396251, + "commit": "c6d9326fd7f4c7925deb5ff4f27f984a073bf6b8", + "contract_digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "workspace_digest": "453dec7743a2e93811de583cf817d2ecdaf85a6ee3b315e5a4966dfe5eb2feec", + "acceptance_input_digest": "a0ecbb0b17e619708358399ba25760a9638101183e4eea783bd7c2d46cf56f48", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + "stale_acceptance_input_digest": "a0ecbb0b17e619708358399ba25760a9638101183e4eea783bd7c2d46cf56f48", + "current_acceptance_input_digest": "8fed4e15ddf1fb73057dd1fcda89f6464e0f7ae15c00ec62a323561a147ce96a" + }, + { + "schema_version": 1, + "change_id": "CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review", + "actor": "leif algo", + "reason": "Align Trust CI to SpecSync 5.1.1 via Trust v1.0.1 and a runner-temp file:// mirror; keep project pin and CI on the same latest SpecSync.", + "timestamp": 1784397197, + "from_state": "accepted", + "to_state": "verifying", + "superseded_approval": { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784397150, + "digest": "bbc61826d284f74a887be499160214984e401f31a7fb1d78ea2464201cad270c", + "note": "Accepted under SpecSync 5.1.1; incomplete 5.0.1 manual archive removed." + }, + "prior_verification": { + "timestamp": 1784397145, + "commit": "8a76d01878593200ff1f1ba2104fea12a30db083", + "contract_digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "workspace_digest": "00103adb8e10e5ba2e183296a6112b25b23b3554206ea7c9a63ed916cb55fbda", + "acceptance_input_digest": "1588bf2a9bea098ca85356f3c17279de5e2703ae5dee34fc79c5d08dba7e2eaa", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": ".attest.json", + "kind": "file", + "mode": 33188, + "payload_digest": "fda17571040ce10c378e009859f92cc33afd67b5c62d3f96510bf9e6e5de0a9f", + "entry_digest": "9d185be1f08f917f1162191bbd90ca325f047bec1cda66f2fc6d0737c08da1ab", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".augur.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "17f6ad5b84b4db012f0e3f398a96a478c1324fd47e72e1dd2a13c7cf9a432983", + "entry_digest": "bac13c952da05292bdd0af5849aad9d9def3ae5afc830fa42b6914b2fd874beb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/ci.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "1f310d5d11b4466aedf85aac75d7db13b07d564f1e38e2f596defb8cf2f06d1c", + "entry_digest": "9abaefb404d6bb884367be7ea7524e890c9bab326c810c0985569c35a83418e7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/trust.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "2466ee51b03676c27a0a0510834e4d2083c017eceee28b223a63665a4e8bb144", + "entry_digest": "51ee76e8a5529942adfd73f19e5dea39fec7de68b18c9cb5773aa28ada4f8789", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "30d23b531c3fcb3e46c413c3d06d3c2848bb273aaf86abdee660e201ed9519a9", + "entry_digest": "8c2aa3eee1fa32d85bddb1f5daf626a0a97ce920f434cd2ec57050fe1623867a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/.gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "a3129d6f93250ade8dbacfc73bc7eeae0cc47c2f7032142ca47cb4f1ffb2483e", + "entry_digest": "9badbf40b83d05f58bafda0fc2cafccfe726e4da7e6e67ef513e822989e13f04", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/change-sequence.json", + "kind": "file", + "mode": 33188, + "payload_digest": "3f711fd3f671890cacd293a97ff33223806fce0ce831a54dbd4aad1eeba79433", + "entry_digest": "ae757f4ebb20a9690f0644cc138231711296318c7beafb7108d256d35cca3797", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/config.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "54a83f6a4a252649bac390d2e936aa0815711fba86b6bfc8ea8fff2fffdfd29b", + "entry_digest": "e60f979233a7db75ce63f4ef42d6f1f7676ad1655a438b9baf78558aba60ec3e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/registry.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "c423be1a5cf87318f85dc252fe0acd1c1486c5224ddc2d8e19bea1ac9c69c820", + "entry_digest": "7e1f068900ced849b8d1028ca40165fbdc5280ae7f53452f0e57e2710d895848", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/sdd.json", + "kind": "file", + "mode": 33188, + "payload_digest": "2d5fb3058b1ee4ce584c3cda9410c193c4893e272ed459205e58bfde06afc7b0", + "entry_digest": "8c6b11fc5787eb04e7ee651eb15fbf98fc3ea22db37e65423e3d75f99c09df19", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/version", + "kind": "file", + "mode": 33188, + "payload_digest": "f9893302cd3158f3b5aea394dcd2a91574869e9e6ff69e9235b10a3bf8c983fb", + "entry_digest": "f980ba79f6c953bed30303c6b87d8e868ad6a7f4114bf0e745c9099255e665b0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".trust.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "6284ced27613c8e2dd8266ffd1668f021cb24e1edb6ccd79c9ade86032c09ce8", + "entry_digest": "7cdd9144620ced58d9ac48ee7d2b8563f5564f1ae2db02a22e7eed781963257e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "AGENTS.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a671dd50eea50f115e6f9abd554e5a8ad7e520208fec5c4bd540c4f3a07ef807", + "entry_digest": "c321960d8ebbf18c2833c8f8b7fe413d6f0e349b424bf2b296a4da7a26316750", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "CLAUDE.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e2df5028858a540821e4a666297d536a14bf598d48afe6c44df921b0f1ddbf32", + "entry_digest": "6930540d6a42ffd8c849bdf10eaf69c3f231cf5e824c9e6f0e694d3edb91bda3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.resolved", + "kind": "file", + "mode": 33188, + "payload_digest": "12eea9fa129e151eaffdc230a234293407f0e3a99c52f15597c72e4e591c0e1e", + "entry_digest": "554d48ebe132641edab54e1d89d163cc2534521a9f41750ed5bd8582723a2d28", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", + "entry_digest": "0b185dd498f42e05a6cc8c2447d547432f4c40000c5dc26f17fe0fc7ae21d6cb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "5fc2d0e776b093053868b00233b9027cbdefd62fb5a0fbb94a802ee59c3101b2", + "entry_digest": "3a2de19f367679d830884d903ac4b0f922c2493928c29e132c33aa4f8c781d0b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Scripts/smoke.sh", + "kind": "file", + "mode": 33261, + "payload_digest": "5947d02b95d6205d63beca54876398d81226d0d4796b4234b646a3b919f08b4c", + "entry_digest": "a847aedf94fa22e35460140f14bdd4be567c550ddc2d20ade0f672329f3efbd7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Sources/aps/Aps.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "68f03f7ec7a10f052e147d57faf5e359e67b7582e06586078b72de53972071b8", + "entry_digest": "e6d8d515e176c6da445f7a402edbabea6e28bacaf74695db6154dcb7c56bced0", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoKey.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "ae5452ba9738ccd90f004a65fcc64f9beeb4366dc8ab6a094be70db2356bc68b", + "entry_digest": "bab68a6071d00c323405116a9ff4380356c8477755850bbc124233ef6c667141", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoState.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "741c2c25af9d89a71e3831cbcec0e7b63efb982caa4c83ae7c7ab31dfbf93924", + "entry_digest": "883c29aefe922beb4e56beb2d3bae3d7ffd5047c05ee3453bbac9dcdfa6483a3", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/Dependencies.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "635340259dcd618bf5099e07dad823f72f4517f6a2762ec1e6b67965221ccef2", + "entry_digest": "637ab3fca33111ebb5f145cdd632e7a6412e99d88d08e3890ab1cc3edc54c736", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/StateStore.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "1eec78c3da61ce03c9d9e0dcfa73b5a946fd9486446566f44f52ff568b66b742", + "entry_digest": "8632b57bb371b7e22f6e0991082590e89e53c29a2a08e5cb28ddb1e6cbca1375", + "owners": [ + "state-store" + ] + }, + { + "path": "Tests/apsTests/APSTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "fc62708d2a2672bbcd27c3a75eb9a41005ae2d6d07cc657ba692e1839d114499", + "entry_digest": "529fbe2c459f55c31654c89244ea030feda05557fab79fda215fe41ed4755573", + "owners": [ + "@exact:test" + ] + }, + { + "path": "fledge.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "f69feb965265eb9481197160885409a03d0eb367149a2955c7b17a98dee9ba4e", + "entry_digest": "4994cce91eb6ed15dcf039ff4ce7194b901fe8e5ef33905503817173f42b6560", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/aps-cli/aps-cli.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "fc2f157fdcb2bc927a7ad41187993690389b2c9a71f4fba6077bcace0b84c1d2", + "entry_digest": "b025cb47565ae0dad36c2adf59145aa898d88782df84e8805489ac76abcbb787", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "6a67354ec782d88510bea4b0ec28e1b1a3c50fc01e625ee32d6783f4dfbc86e0", + "entry_digest": "9cb95bb0d687799ba10637230b404cbef8a5abfb45d46a07a7bb50bee9703431", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "99f67a96136a4f15785230b61b5c74d57ccac1ad05877513097ff0280de510da", + "entry_digest": "c0c5fe71d6b614fe5e90a5c3ebba3b173a7253255b90c9748144d96ff366915e", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "b6f0c8e3aa90f43e5dc40389e77088b2ec6ebb725c89c57217970fc1c221f527", + "entry_digest": "af31087c96d633274df81aecd4e99f520a55995882545190d2d42bb30fa5c3aa", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "14420af80f34d7954894aaf63f9864db13eea74549796043f54badf82805394a", + "entry_digest": "1227fad23fad49d312453dfe8fffc2bfe67396fdb29c88dab355bd60e8ec91b5", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/state-store/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "ddb4564d168db43eadd6315a7f56b532198905a79abebfee77db890db0f9c402", + "entry_digest": "a14edf94507dfd13d7d325bf68e370e0c1646e323b28341bd0c1dfff72f05d88", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "dfa974ed7b0c6488ba70d0f6cac9f574c4df29674612abeef1ec12dd89f8241a", + "entry_digest": "75cc7a8c3022b64210eab987dd93f655fb812deb45b7f79d064456e4539b6157", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/state-store.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "22e65ea3a60cd05e76d0450c8136609bd06257eb70a5ac624b8ba25ff4337cba", + "entry_digest": "010f681da95cc42be632e117cc6b41f2fa4abd33a62a30400a1c583479a65369", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "711db2a24a4959531ca966ac43d96e7817788ebe74077280a6cff950cb9a8779", + "entry_digest": "8402318068cd8ab6f8a596519289e70425dbc28bf6b31d5c1ef6f0a17f927f74", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "96fbc44cdbe25dfab52a47f8efdbd4698203571981b181c78a04769112402f1d", + "entry_digest": "8b0abd2a0f6613b9caa1f2831cdf8776b80a1945552eade241ff3d3b8d6404af", + "owners": [ + "state-store" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + "stale_acceptance_input_digest": "1588bf2a9bea098ca85356f3c17279de5e2703ae5dee34fc79c5d08dba7e2eaa", + "current_acceptance_input_digest": "b4503835c81ef2983e6deee01231adb7c39f133c1c4b3fbd7d149a09ac6f7c60" + }, + { + "schema_version": 1, + "change_id": "CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review", + "actor": "leif algo", + "reason": "Document SpecSync 5.1.1 local pin in README after Trust CI mirror wiring.", + "timestamp": 1784397241, + "from_state": "accepted", + "to_state": "verifying", + "superseded_approval": { + "gate": "acceptance", + "actor": "leif algo", + "timestamp": 1784397208, + "digest": "2a023c4ceb638ee95b162ef18367cb5338e75124bee1a189fbc6aab47e30bdd0", + "note": "Accepted SpecSync 5.1.1 project pin with Trust v1.0.1 CI mirror; incomplete 5.0.1 manual archive removed." + }, + "prior_verification": { + "timestamp": 1784397207, + "commit": "8a76d01878593200ff1f1ba2104fea12a30db083", + "contract_digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "workspace_digest": "cfcca5e750e6b8e46ae8df74f0d7ffa9133287c5a38c8437f74e8c129303a676", + "acceptance_input_digest": "b4503835c81ef2983e6deee01231adb7c39f133c1c4b3fbd7d149a09ac6f7c60", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": ".attest.json", + "kind": "file", + "mode": 33188, + "payload_digest": "fda17571040ce10c378e009859f92cc33afd67b5c62d3f96510bf9e6e5de0a9f", + "entry_digest": "9d185be1f08f917f1162191bbd90ca325f047bec1cda66f2fc6d0737c08da1ab", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".augur.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "17f6ad5b84b4db012f0e3f398a96a478c1324fd47e72e1dd2a13c7cf9a432983", + "entry_digest": "bac13c952da05292bdd0af5849aad9d9def3ae5afc830fa42b6914b2fd874beb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/ci.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "1f310d5d11b4466aedf85aac75d7db13b07d564f1e38e2f596defb8cf2f06d1c", + "entry_digest": "9abaefb404d6bb884367be7ea7524e890c9bab326c810c0985569c35a83418e7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/trust.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "e165929994150d856d05ad048d8e1032e09df989c78ea3f1390d4e885b50af56", + "entry_digest": "e405b6225fdb502cfae9b22a9c14e21be8d1715bbaf8d56cdfd178bb8e173cb9", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "30d23b531c3fcb3e46c413c3d06d3c2848bb273aaf86abdee660e201ed9519a9", + "entry_digest": "8c2aa3eee1fa32d85bddb1f5daf626a0a97ce920f434cd2ec57050fe1623867a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/.gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "a3129d6f93250ade8dbacfc73bc7eeae0cc47c2f7032142ca47cb4f1ffb2483e", + "entry_digest": "9badbf40b83d05f58bafda0fc2cafccfe726e4da7e6e67ef513e822989e13f04", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/change-sequence.json", + "kind": "file", + "mode": 33188, + "payload_digest": "3f711fd3f671890cacd293a97ff33223806fce0ce831a54dbd4aad1eeba79433", + "entry_digest": "ae757f4ebb20a9690f0644cc138231711296318c7beafb7108d256d35cca3797", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/config.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "54a83f6a4a252649bac390d2e936aa0815711fba86b6bfc8ea8fff2fffdfd29b", + "entry_digest": "e60f979233a7db75ce63f4ef42d6f1f7676ad1655a438b9baf78558aba60ec3e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/registry.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "c423be1a5cf87318f85dc252fe0acd1c1486c5224ddc2d8e19bea1ac9c69c820", + "entry_digest": "7e1f068900ced849b8d1028ca40165fbdc5280ae7f53452f0e57e2710d895848", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/sdd.json", + "kind": "file", + "mode": 33188, + "payload_digest": "2d5fb3058b1ee4ce584c3cda9410c193c4893e272ed459205e58bfde06afc7b0", + "entry_digest": "8c6b11fc5787eb04e7ee651eb15fbf98fc3ea22db37e65423e3d75f99c09df19", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/version", + "kind": "file", + "mode": 33188, + "payload_digest": "f9893302cd3158f3b5aea394dcd2a91574869e9e6ff69e9235b10a3bf8c983fb", + "entry_digest": "f980ba79f6c953bed30303c6b87d8e868ad6a7f4114bf0e745c9099255e665b0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".trust.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "6284ced27613c8e2dd8266ffd1668f021cb24e1edb6ccd79c9ade86032c09ce8", + "entry_digest": "7cdd9144620ced58d9ac48ee7d2b8563f5564f1ae2db02a22e7eed781963257e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "AGENTS.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a671dd50eea50f115e6f9abd554e5a8ad7e520208fec5c4bd540c4f3a07ef807", + "entry_digest": "c321960d8ebbf18c2833c8f8b7fe413d6f0e349b424bf2b296a4da7a26316750", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "CLAUDE.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e2df5028858a540821e4a666297d536a14bf598d48afe6c44df921b0f1ddbf32", + "entry_digest": "6930540d6a42ffd8c849bdf10eaf69c3f231cf5e824c9e6f0e694d3edb91bda3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.resolved", + "kind": "file", + "mode": 33188, + "payload_digest": "12eea9fa129e151eaffdc230a234293407f0e3a99c52f15597c72e4e591c0e1e", + "entry_digest": "554d48ebe132641edab54e1d89d163cc2534521a9f41750ed5bd8582723a2d28", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", + "entry_digest": "0b185dd498f42e05a6cc8c2447d547432f4c40000c5dc26f17fe0fc7ae21d6cb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "b673a3e3ad2964ca4fc0f8051d991edb321e42c3ffdc4a44c30d30449ab3eeb5", + "entry_digest": "8f011e80ca45a367403be199dd16fd7216064d746506a08e8de739fbeaf162da", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Scripts/smoke.sh", + "kind": "file", + "mode": 33261, + "payload_digest": "5947d02b95d6205d63beca54876398d81226d0d4796b4234b646a3b919f08b4c", + "entry_digest": "a847aedf94fa22e35460140f14bdd4be567c550ddc2d20ade0f672329f3efbd7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Sources/aps/Aps.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "68f03f7ec7a10f052e147d57faf5e359e67b7582e06586078b72de53972071b8", + "entry_digest": "e6d8d515e176c6da445f7a402edbabea6e28bacaf74695db6154dcb7c56bced0", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoKey.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "ae5452ba9738ccd90f004a65fcc64f9beeb4366dc8ab6a094be70db2356bc68b", + "entry_digest": "bab68a6071d00c323405116a9ff4380356c8477755850bbc124233ef6c667141", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoState.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "741c2c25af9d89a71e3831cbcec0e7b63efb982caa4c83ae7c7ab31dfbf93924", + "entry_digest": "883c29aefe922beb4e56beb2d3bae3d7ffd5047c05ee3453bbac9dcdfa6483a3", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/Dependencies.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "635340259dcd618bf5099e07dad823f72f4517f6a2762ec1e6b67965221ccef2", + "entry_digest": "637ab3fca33111ebb5f145cdd632e7a6412e99d88d08e3890ab1cc3edc54c736", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/StateStore.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "1eec78c3da61ce03c9d9e0dcfa73b5a946fd9486446566f44f52ff568b66b742", + "entry_digest": "8632b57bb371b7e22f6e0991082590e89e53c29a2a08e5cb28ddb1e6cbca1375", + "owners": [ + "state-store" + ] + }, + { + "path": "Tests/apsTests/APSTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "fc62708d2a2672bbcd27c3a75eb9a41005ae2d6d07cc657ba692e1839d114499", + "entry_digest": "529fbe2c459f55c31654c89244ea030feda05557fab79fda215fe41ed4755573", + "owners": [ + "@exact:test" + ] + }, + { + "path": "fledge.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "f69feb965265eb9481197160885409a03d0eb367149a2955c7b17a98dee9ba4e", + "entry_digest": "4994cce91eb6ed15dcf039ff4ce7194b901fe8e5ef33905503817173f42b6560", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/aps-cli/aps-cli.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "fc2f157fdcb2bc927a7ad41187993690389b2c9a71f4fba6077bcace0b84c1d2", + "entry_digest": "b025cb47565ae0dad36c2adf59145aa898d88782df84e8805489ac76abcbb787", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "6a67354ec782d88510bea4b0ec28e1b1a3c50fc01e625ee32d6783f4dfbc86e0", + "entry_digest": "9cb95bb0d687799ba10637230b404cbef8a5abfb45d46a07a7bb50bee9703431", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "99f67a96136a4f15785230b61b5c74d57ccac1ad05877513097ff0280de510da", + "entry_digest": "c0c5fe71d6b614fe5e90a5c3ebba3b173a7253255b90c9748144d96ff366915e", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "b6f0c8e3aa90f43e5dc40389e77088b2ec6ebb725c89c57217970fc1c221f527", + "entry_digest": "af31087c96d633274df81aecd4e99f520a55995882545190d2d42bb30fa5c3aa", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "14420af80f34d7954894aaf63f9864db13eea74549796043f54badf82805394a", + "entry_digest": "1227fad23fad49d312453dfe8fffc2bfe67396fdb29c88dab355bd60e8ec91b5", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/state-store/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "ddb4564d168db43eadd6315a7f56b532198905a79abebfee77db890db0f9c402", + "entry_digest": "a14edf94507dfd13d7d325bf68e370e0c1646e323b28341bd0c1dfff72f05d88", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "dfa974ed7b0c6488ba70d0f6cac9f574c4df29674612abeef1ec12dd89f8241a", + "entry_digest": "75cc7a8c3022b64210eab987dd93f655fb812deb45b7f79d064456e4539b6157", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/state-store.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "22e65ea3a60cd05e76d0450c8136609bd06257eb70a5ac624b8ba25ff4337cba", + "entry_digest": "010f681da95cc42be632e117cc6b41f2fa4abd33a62a30400a1c583479a65369", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "711db2a24a4959531ca966ac43d96e7817788ebe74077280a6cff950cb9a8779", + "entry_digest": "8402318068cd8ab6f8a596519289e70425dbc28bf6b31d5c1ef6f0a17f927f74", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "96fbc44cdbe25dfab52a47f8efdbd4698203571981b181c78a04769112402f1d", + "entry_digest": "8b0abd2a0f6613b9caa1f2831cdf8776b80a1945552eade241ff3d3b8d6404af", + "owners": [ + "state-store" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + "stale_acceptance_input_digest": "b4503835c81ef2983e6deee01231adb7c39f133c1c4b3fbd7d149a09ac6f7c60", + "current_acceptance_input_digest": "b0acb6b35cd8a84250c1fa20cca529be2154e3eb5e1a555531ee1624d327572e" } ] } diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/state.json b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/state.json index 7a0454c..5c6f315 100644 --- a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/state.json +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/state.json @@ -6,9 +6,10 @@ "description": "Fix FileState watch cache and path isolation from review", "kind": "feature", "state": "accepted", + "canonical_applied": true, "base_commit": "c6d9326fd7f4c7925deb5ff4f27f984a073bf6b8", "created_at": 1784396041, - "updated_at": 1784396251, + "updated_at": 1784397245, "affected_specs": [ "aps-cli", "state-store" diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification-attempts.json b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification-attempts.json new file mode 100644 index 0000000..2f5337b --- /dev/null +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification-attempts.json @@ -0,0 +1,89 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1784397102, + "commit": "8a76d01878593200ff1f1ba2104fea12a30db083", + "contract_digest": "80cda71fb38070ef0014a9230a3c5f96ed00a7b41e6e8a88cd722533f0097d24", + "workspace_digest": "00103adb8e10e5ba2e183296a6112b25b23b3554206ea7c9a63ed916cb55fbda", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + { + "timestamp": 1784397145, + "commit": "8a76d01878593200ff1f1ba2104fea12a30db083", + "contract_digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "workspace_digest": "00103adb8e10e5ba2e183296a6112b25b23b3554206ea7c9a63ed916cb55fbda", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + { + "timestamp": 1784397207, + "commit": "8a76d01878593200ff1f1ba2104fea12a30db083", + "contract_digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "workspace_digest": "cfcca5e750e6b8e46ae8df74f0d7ffa9133287c5a38c8437f74e8c129303a676", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-003", + "REQ-state-store-004" + ] + }, + { + "timestamp": 1784397244, + "commit": "8a76d01878593200ff1f1ba2104fea12a30db083", + "contract_digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", + "workspace_digest": "91ba3c897a1d5599c3bcd61040b00e73767d6698b1266510ff07e2b7b6a9ddad", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-aps-cli-004", + "REQ-aps-cli-005", + "REQ-state-store-001", + "REQ-state-store-003", + "REQ-state-store-004" + ] + } + ] +} diff --git a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification.json b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification.json index 72d8e8f..a57920f 100644 --- a/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification.json +++ b/.specsync/changes/CHG-0002-fix-filestate-watch-cache-and-path-isolation-from-review/verification.json @@ -1,9 +1,364 @@ { - "timestamp": 1784396251, - "commit": "c6d9326fd7f4c7925deb5ff4f27f984a073bf6b8", + "timestamp": 1784397244, + "commit": "8a76d01878593200ff1f1ba2104fea12a30db083", "contract_digest": "6d4175cb4100733aee98f1debbdd8aa5736bfc235a4e21bc742b76b66195c817", - "workspace_digest": "453dec7743a2e93811de583cf817d2ecdaf85a6ee3b315e5a4966dfe5eb2feec", - "acceptance_input_digest": "a0ecbb0b17e619708358399ba25760a9638101183e4eea783bd7c2d46cf56f48", + "workspace_digest": "91ba3c897a1d5599c3bcd61040b00e73767d6698b1266510ff07e2b7b6a9ddad", + "acceptance_input_digest": "b0acb6b35cd8a84250c1fa20cca529be2154e3eb5e1a555531ee1624d327572e", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": ".attest.json", + "kind": "file", + "mode": 33188, + "payload_digest": "fda17571040ce10c378e009859f92cc33afd67b5c62d3f96510bf9e6e5de0a9f", + "entry_digest": "9d185be1f08f917f1162191bbd90ca325f047bec1cda66f2fc6d0737c08da1ab", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".augur.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "17f6ad5b84b4db012f0e3f398a96a478c1324fd47e72e1dd2a13c7cf9a432983", + "entry_digest": "bac13c952da05292bdd0af5849aad9d9def3ae5afc830fa42b6914b2fd874beb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/ci.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "1f310d5d11b4466aedf85aac75d7db13b07d564f1e38e2f596defb8cf2f06d1c", + "entry_digest": "9abaefb404d6bb884367be7ea7524e890c9bab326c810c0985569c35a83418e7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".github/workflows/trust.yml", + "kind": "file", + "mode": 33188, + "payload_digest": "e165929994150d856d05ad048d8e1032e09df989c78ea3f1390d4e885b50af56", + "entry_digest": "e405b6225fdb502cfae9b22a9c14e21be8d1715bbaf8d56cdfd178bb8e173cb9", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "30d23b531c3fcb3e46c413c3d06d3c2848bb273aaf86abdee660e201ed9519a9", + "entry_digest": "8c2aa3eee1fa32d85bddb1f5daf626a0a97ce920f434cd2ec57050fe1623867a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/.gitignore", + "kind": "file", + "mode": 33188, + "payload_digest": "a3129d6f93250ade8dbacfc73bc7eeae0cc47c2f7032142ca47cb4f1ffb2483e", + "entry_digest": "9badbf40b83d05f58bafda0fc2cafccfe726e4da7e6e67ef513e822989e13f04", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/change-sequence.json", + "kind": "file", + "mode": 33188, + "payload_digest": "3f711fd3f671890cacd293a97ff33223806fce0ce831a54dbd4aad1eeba79433", + "entry_digest": "ae757f4ebb20a9690f0644cc138231711296318c7beafb7108d256d35cca3797", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/config.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "54a83f6a4a252649bac390d2e936aa0815711fba86b6bfc8ea8fff2fffdfd29b", + "entry_digest": "e60f979233a7db75ce63f4ef42d6f1f7676ad1655a438b9baf78558aba60ec3e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/registry.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "c423be1a5cf87318f85dc252fe0acd1c1486c5224ddc2d8e19bea1ac9c69c820", + "entry_digest": "7e1f068900ced849b8d1028ca40165fbdc5280ae7f53452f0e57e2710d895848", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/sdd.json", + "kind": "file", + "mode": 33188, + "payload_digest": "2d5fb3058b1ee4ce584c3cda9410c193c4893e272ed459205e58bfde06afc7b0", + "entry_digest": "8c6b11fc5787eb04e7ee651eb15fbf98fc3ea22db37e65423e3d75f99c09df19", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".specsync/version", + "kind": "file", + "mode": 33188, + "payload_digest": "f9893302cd3158f3b5aea394dcd2a91574869e9e6ff69e9235b10a3bf8c983fb", + "entry_digest": "f980ba79f6c953bed30303c6b87d8e868ad6a7f4114bf0e745c9099255e665b0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": ".trust.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "6284ced27613c8e2dd8266ffd1668f021cb24e1edb6ccd79c9ade86032c09ce8", + "entry_digest": "7cdd9144620ced58d9ac48ee7d2b8563f5564f1ae2db02a22e7eed781963257e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "AGENTS.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a671dd50eea50f115e6f9abd554e5a8ad7e520208fec5c4bd540c4f3a07ef807", + "entry_digest": "c321960d8ebbf18c2833c8f8b7fe413d6f0e349b424bf2b296a4da7a26316750", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "CLAUDE.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e2df5028858a540821e4a666297d536a14bf598d48afe6c44df921b0f1ddbf32", + "entry_digest": "6930540d6a42ffd8c849bdf10eaf69c3f231cf5e824c9e6f0e694d3edb91bda3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.resolved", + "kind": "file", + "mode": 33188, + "payload_digest": "12eea9fa129e151eaffdc230a234293407f0e3a99c52f15597c72e4e591c0e1e", + "entry_digest": "554d48ebe132641edab54e1d89d163cc2534521a9f41750ed5bd8582723a2d28", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Package.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "26c8955179127e90c5b2750191b7ffa99d5d6a0c43b82a93fd3731334426e8e1", + "entry_digest": "0b185dd498f42e05a6cc8c2447d547432f4c40000c5dc26f17fe0fc7ae21d6cb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "658cdb35f5117c19dd9688ce79fba502029d0ca34789482a333017d155ad99d8", + "entry_digest": "3e8da8bd1905678d7101a98942b04342ef85182909091d2307fd5018438fefa9", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Scripts/smoke.sh", + "kind": "file", + "mode": 33261, + "payload_digest": "5947d02b95d6205d63beca54876398d81226d0d4796b4234b646a3b919f08b4c", + "entry_digest": "a847aedf94fa22e35460140f14bdd4be567c550ddc2d20ade0f672329f3efbd7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "Sources/aps/Aps.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "68f03f7ec7a10f052e147d57faf5e359e67b7582e06586078b72de53972071b8", + "entry_digest": "e6d8d515e176c6da445f7a402edbabea6e28bacaf74695db6154dcb7c56bced0", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoKey.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "ae5452ba9738ccd90f004a65fcc64f9beeb4366dc8ab6a094be70db2356bc68b", + "entry_digest": "bab68a6071d00c323405116a9ff4380356c8477755850bbc124233ef6c667141", + "owners": [ + "aps-cli" + ] + }, + { + "path": "Sources/aps/DemoState.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "741c2c25af9d89a71e3831cbcec0e7b63efb982caa4c83ae7c7ab31dfbf93924", + "entry_digest": "883c29aefe922beb4e56beb2d3bae3d7ffd5047c05ee3453bbac9dcdfa6483a3", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/Dependencies.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "635340259dcd618bf5099e07dad823f72f4517f6a2762ec1e6b67965221ccef2", + "entry_digest": "637ab3fca33111ebb5f145cdd632e7a6412e99d88d08e3890ab1cc3edc54c736", + "owners": [ + "state-store" + ] + }, + { + "path": "Sources/aps/StateStore.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "1eec78c3da61ce03c9d9e0dcfa73b5a946fd9486446566f44f52ff568b66b742", + "entry_digest": "8632b57bb371b7e22f6e0991082590e89e53c29a2a08e5cb28ddb1e6cbca1375", + "owners": [ + "state-store" + ] + }, + { + "path": "Tests/apsTests/APSTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "fc62708d2a2672bbcd27c3a75eb9a41005ae2d6d07cc657ba692e1839d114499", + "entry_digest": "529fbe2c459f55c31654c89244ea030feda05557fab79fda215fe41ed4755573", + "owners": [ + "@exact:test" + ] + }, + { + "path": "fledge.toml", + "kind": "file", + "mode": 33188, + "payload_digest": "f69feb965265eb9481197160885409a03d0eb367149a2955c7b17a98dee9ba4e", + "entry_digest": "4994cce91eb6ed15dcf039ff4ce7194b901fe8e5ef33905503817173f42b6560", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/aps-cli/aps-cli.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "fc2f157fdcb2bc927a7ad41187993690389b2c9a71f4fba6077bcace0b84c1d2", + "entry_digest": "b025cb47565ae0dad36c2adf59145aa898d88782df84e8805489ac76abcbb787", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "6a67354ec782d88510bea4b0ec28e1b1a3c50fc01e625ee32d6783f4dfbc86e0", + "entry_digest": "9cb95bb0d687799ba10637230b404cbef8a5abfb45d46a07a7bb50bee9703431", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "99f67a96136a4f15785230b61b5c74d57ccac1ad05877513097ff0280de510da", + "entry_digest": "c0c5fe71d6b614fe5e90a5c3ebba3b173a7253255b90c9748144d96ff366915e", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "b6f0c8e3aa90f43e5dc40389e77088b2ec6ebb725c89c57217970fc1c221f527", + "entry_digest": "af31087c96d633274df81aecd4e99f520a55995882545190d2d42bb30fa5c3aa", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/aps-cli/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "14420af80f34d7954894aaf63f9864db13eea74549796043f54badf82805394a", + "entry_digest": "1227fad23fad49d312453dfe8fffc2bfe67396fdb29c88dab355bd60e8ec91b5", + "owners": [ + "aps-cli" + ] + }, + { + "path": "specs/state-store/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "ddb4564d168db43eadd6315a7f56b532198905a79abebfee77db890db0f9c402", + "entry_digest": "a14edf94507dfd13d7d325bf68e370e0c1646e323b28341bd0c1dfff72f05d88", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "dfa974ed7b0c6488ba70d0f6cac9f574c4df29674612abeef1ec12dd89f8241a", + "entry_digest": "75cc7a8c3022b64210eab987dd93f655fb812deb45b7f79d064456e4539b6157", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/state-store.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "22e65ea3a60cd05e76d0450c8136609bd06257eb70a5ac624b8ba25ff4337cba", + "entry_digest": "010f681da95cc42be632e117cc6b41f2fa4abd33a62a30400a1c583479a65369", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "711db2a24a4959531ca966ac43d96e7817788ebe74077280a6cff950cb9a8779", + "entry_digest": "8402318068cd8ab6f8a596519289e70425dbc28bf6b31d5c1ef6f0a17f927f74", + "owners": [ + "state-store" + ] + }, + { + "path": "specs/state-store/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "96fbc44cdbe25dfab52a47f8efdbd4698203571981b181c78a04769112402f1d", + "entry_digest": "8b0abd2a0f6613b9caa1f2831cdf8776b80a1945552eade241ff3d3b8d6404af", + "owners": [ + "state-store" + ] + } + ] + }, "passed": true, "commands": [ { diff --git a/.specsync/version b/.specsync/version index 6b244dc..ac14c3d 100644 --- a/.specsync/version +++ b/.specsync/version @@ -1 +1 @@ -5.0.1 +5.1.1 diff --git a/README.md b/README.md index 4b25680..ae5f9be 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Dynamic / user-declared keys are intentionally out of scope for v1. - Swift 6.0+ - macOS 14+ (CI). Linux toolchains are supported best-effort, not gated in CI yet. - For the trust gate locally: [corvid-trust](https://github.com/CorvidLabs/trust) (`brew install CorvidLabs/tap/corvid-trust`) +- SpecSync **5.1.1** (see `.specsync/version`). Trust CI mirrors that exact release; brew `spec-sync` latest should match. ## Build and run @@ -105,7 +106,7 @@ Before making the repo public, switch off self-hosted runners for fork pull requ | `.trust.toml` | Unified Trust policy | | `.augur.toml` | Diff-risk thresholds | | `.attest.json` | Provenance policy | -| `.specsync/` | SpecSync 5 config + SDD change tracking | +| `.specsync/` | SpecSync 5.1.1 config + SDD change tracking (`.specsync/version`) | | `specs/` | Module contracts (`aps-cli`, `state-store`) | | `AGENTS.md` | Standing rules (managed block required by CI) |